2017-02-20 12 views
1
public class MyService 
{ 
    private readonly ISomething _something; 
    private readonly Func<IRarelyGetUsed> _rarelyGetUsed; 

    public MyService(ISomething something, Func<IRarelyGetUsed> rarelyGetUsed) 
    { 
     _something = something; 
     _rarelyGetUsed = rarelyGetUsed; 
    } 
} 

を使用して依存関係を持っているとき、私たちはIOCのためAutofacを使用し失敗し、それがされるまで、これらの依存関係が解決されませんので、我々はFunc<T>アプローチを使用して、大きなパフォーマンス向上(負荷時)を得ることができましたいくつかのシナリオでは、特定の依存関係は使用されません。部品番号のCreateInstanceは、コンストラクタはのFunc <T>

また、ユニットテストにはMoqを使用しています。それが吹くこの時点で

var _container = new AutoMocker(); 
var _service = _container.CreateInstance<MyService>(); 

- のFuncの依存関係とうまくプレイする部品番号を伝えるためにどのようにSystem.NullReferenceException : Object reference not set to an instance of an object.

誰もが知っていますか?

Func<IRarelyGetUsed>からIRarelyGetUsedに変更する場合は例外ではありません。

編集:ナゲットパッケージはかなり古いです - パッケージをアップデートした後https://github.com/tkellogg/Moq.AutoMockerこれは現在動作しています。でセットアップするには、上記の方法結果の結果をしようと

_container.GetMock<Func<IRarelyGetUsed>>().Setup(p => p().DoSomething(It.IsAny<string>())).Returns(true).Verifiable(); 

- -

しかし、解決するためのもう一つの問題がありますUnable to cast object of type 'System.Linq.Expressions.InstanceMethodCallExpressionN' to type 'System.Linq.Expressions.InvocationExpression'

編集2:

var serviceMock = _container.GetMock<IRarelyGetUsed>(); 
serviceMock.Setup(r => r.DoSomething()).Returns(someData); 
_container.GetMock<Func<IRarelyGetUsed>>().Setup(s => s()).Returns(serviceMock.Object); 

上記の機能は動作しますが、Func<IRarelyGetUsed>との両方を設定する必要があります210 - 1つだけ行う必要がある場合はいいでしょう。それ以外の場合は、テストごとにオーバーヘッドが増えます。

+1

編集内容は、意味をなさないデリゲート(Func)とあなたが嘲笑したい実際のものを設定します。おそらく、 'SetupFunc (Mock mock、object returnData)'のような 'AutoMocker'の拡張メソッドを書くことができます。これは、編集2で書き留めた定型コードです。 – Scott

答えて

2

あなたは自動的にAutoMockerはこのような何かやっておきTためFunc<T>を配線することができます

public void RegisterFuncs(AutoMocker autoMocker, IEnumerable<Type> types) 
{ 
    var use = typeof(AutoMocker).GetMethods() 
     .First(t => t.Name == "Use" && 
        t.GetGenericArguments().First().Name == "TService"); 
    var get = typeof(AutoMocker).GetMethod("Get"); 
    foreach (var type in types) 
    { 
     // _.container.Use<Func<T>>() 
     var typedUse = use.MakeGenericMethod(typeof(Func<>).MakeGenericType(type)); 

     // _container.Get<T>() 
     var typedGet = get.MakeGenericMethod(type); 
     var target = Expression.Constant(autoMocker); 
     var call = Expression.Call(target, typedGet); 

     //() => _container.Get<T>() 
     var lambda = Expression.Lambda(call); 

     // _.container.Use<Func<T>>(() => _container.Get<T>()) 
     typedUse.Invoke(autoMocker, new object[] { lambda.Compile() }); 
    } 
} 

// Then call with your AutoMocker instance and the interfaces you want to wire up 
var types = typeof(SomeNamespace.ISomeInterface).Assembly.GetExportedTypes() 
    .Where(t => t.IsInterface && !t.ContainsGenericParameters); 
RegisterFuncs(yourAutoMocker, types); 

だけのコンテナを作成した後、あなたのテストのセットアップでこれを実行します。

注:以下のようなものが必要になりますので、Lazy<T>については、上記の作業をするために、あなたは、Func<T>Lazy<T>をインスタンス化する必要があります:あなたは確かに持っているよう

public void RegisterLazys(AutoMocker autoMocker, IEnumerable<Type> types) 
{ 
    var use = typeof(AutoMocker).GetMethods() 
     .First(t => t.Name == "Use" && 
        t.GetGenericArguments().First().Name == "TService"); 
    var get = typeof(AutoMocker).GetMethod("Get"); 
    foreach (var type in types) 
    { 
     // Lazy<T> 
     var lazyT = typeof(Lazy<>).MakeGenericType(type); 

     // _.container.Use<Lazy<T>>() 
     var typedUse = use.MakeGenericMethod(lazyT); 

     // _container.Get<T>() 
     var typedGet = get.MakeGenericMethod(type); 
     var target = Expression.Constant(autoMocker); 
     var call = Expression.Call(target, typedGet); 

     //() => _container.Get<T>() 
     var lambda = Expression.Lambda(call); 

     // _.container.Use<Lazy<T>>(new Lazy<T>(() => _container.Get<T>())); 
     typedUse.Invoke(autoMocker, new object[] { Activator.CreateInstance(lazyT, lambda.Compile()) }); 
    } 
} 
0

Func<T>の代わりにLazy<T>を使用して、目的のレイジーローディングを試しましたか? FunkよりMoqのほうが良いかもしれません。

Documentation on Lazy

+0

私の最新編集によれば、しかし、複数のものを設定する必要があるのはちょっと面倒です。私は 'Lazy 'を試してみて、同じ問題が発生すると考えています。しかし私は 'Lazy ' vs 'Func 'をパフォーマンスの観点から調査しています。 – acarter

+0

そうでない場合は、とにかく 'Lazy 'に切り替えることをお勧めします。そうすれば、コードの意図がより明確になります。 – Scott

関連する問題