2016-05-24 3 views
3

ChannelFactory<IService>を嘲笑するときにTargetInvocationExceptionがスローされる理由は?コール毎Serviceインスタンスを作成するために、並行性の面でより安全だ私には思える原因TargetInvocationException moockでChannelFactoryを

public interface IService 
{ 
    void Do(); 
} 

public class Service : IService 
{ 
    private ChannelFactory<IRemoteService> factory; 

    public Service(ChannelFactory<IRemoteService> factory) 
    { 
     this.factory = factory; 
    } 

    public void Do() 
    { 
     using (var remote = factory.CreateChannel()) 
     { 
      remote.DoRemote(); 
     } 
    } 
} 

[TestFixture] 
public class ChannelFactoryMoqTest 
{ 
    private IService service; 
    private Mock<ChannelFactory<IRemoteService>> factory; 

    [Test] 
    public void Test() 
    { 
     this.factory = new Mock<ChannelFactory<IRemoteService>>(); 

     this.service = new Service(this.factory.Object); 
     // Calling Object on this.factory throws TargetInvocationException 
    } 
} 

は私ではなく、単純なIRemoteServiceChannelFactory依存関係を使用します。ここで

は、例外スタックトレースです:

System.Reflection.TargetInvocationException was unhandled by user code 
    HResult=-2146232828 
    Message=Exception has been thrown by the target of an invocation. 
    Source=mscorlib 
    StackTrace: 
     at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor) 
     at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) 
     at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes, StackCrawlMark& stackMark) 
     at System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes) 
     at System.Activator.CreateInstance(Type type, Object[] args) 
     at Castle.DynamicProxy.ProxyGenerator.CreateClassProxyInstance(Type proxyType, List`1 proxyArguments, Type classToProxy, Object[] constructorArguments) 
     at Castle.DynamicProxy.ProxyGenerator.CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options, Object[] constructorArguments, IInterceptor[] interceptors) 
     at Moq.Proxy.CastleProxyFactory.CreateProxy(Type mockType, ICallInterceptor interceptor, Type[] interfaces, Object[] arguments) 
     at Moq.Mock`1.<InitializeInstance>b__2() 
     at Moq.PexProtector.Invoke(Action action) 
     at Moq.Mock`1.InitializeInstance() 
     at Moq.Mock`1.OnGetObject() 
     at Moq.Mock.GetObject() 
     at Moq.Mock.get_Object() 
     at Moq.Mock`1.get_Object() 
     at TR.Eikon.Services.AppVersion.Tests.Workflows.ChannelFactoryMoqTest.Test() in d:\Temp.cs:line 61 
    InnerException: System.NullReferenceException 
     HResult=-2147467261 
     Message=Object reference not set to an instance of an object. 
     Source=System.ServiceModel 
     StackTrace: 
      at System.ServiceModel.ChannelFactory.EnsureSecurityCredentialsManager(ServiceEndpoint endpoint) 
      at System.ServiceModel.ChannelFactory.InitializeEndpoint(String configurationName, EndpointAddress address) 
      at System.ServiceModel.ChannelFactory`1..ctor() 
      at Castle.Proxies.ChannelFactory`1Proxy..ctor(IInterceptor[]) 
     InnerException: 
+2

例外の内容を表示します。クラスが抽象クラスではないため、Moqは実行可能なモックを作成できない可能性が最も高いです。あなたはもっともっと模倣可能な 'IChannelFactory 'を使って調べることもできます。 – Nkosi

+0

@Nkosi私はIChannelFactoryを使用して終了しましたが、CreateChannelと同じシグネチャはありません 例外を見ると、抽象クラスではないもののように見えます。 –

+1

内部例外の直前のスタックトレースを見ると、Moqはデフォルトのコンストラクタを使用してインスタンスを作成しようとしていますが、設定ファイルから取得することを想定して初期化メソッドを呼び出そうとしています。これは、デフォルトのコンストラクタを使用するときに、設定ファイル内の設定を検索するため、予想通りです。 – Nkosi

答えて

3

ChannelFactoryは、それに関連付けられた非既存のエンドポイントに実際のプロキシを作成しようとしているので、あなたはそのエラーを受けています。

私が提案しているのは、制御しているインターフェイスの背後にあるクライアントからChannelFactory<IRemoteService>を隠したり分離したりして、必要なAPIをよりうまく管理できるようにすることです。こうすることで、実際のプロキシの代わりにモックを作成するクライアントに、ファクトリを置き換えることができます。あなたのリファクタリングサービスクラスがあなたの新しいmockableインタフェースを参照します

public class ChannelFactoryWrapper<TChannel> : IMyChannelFactory<TChannel> { 
    private ChannelFactory<TChannel> factory; 
    public ChannelFactoryWrapper(ChannelFactory<TChannel> factory) { 
     this.factory = factory; 
    } 

    public TChannel CreateChannel() { 
     return factory.CreateChannel(); 
    } 
} 

public interface IMyChannelFactory<TChannel> { 
    TChannel CreateChannel(); 
} 

...それは後でChannelFactory<IRemoteService>の実際のインスタンスをラップすることができます... ...

public class Service : IService { 
    private IMyChannelFactory<IRemoteService> factory; 

    public Service(IMyChannelFactory<IRemoteService> factory) { 
     this.factory = factory; 
    } 

    public void Do() { 
     using (var remote = factory.CreateChannel()) { 
      remote.DoRemote(); 
     } 
    } 
} 

...あなたのテストは、リファクタリングされ、それに応じてテストされる可能性があります...

[Test] 
public void Should_Mock_ChannelFactory() { 
    //Arrange 
    var remoteService = new Mock<IRemoteService>(); 
    remoteService.Setup(m => m.DoRemote()).Verifiable(); 
    var factory = new Mock<IMyChannelFactory<IRemoteService>>(); 
    factory.Setup(f => f.CreateChannel()).Returns(remoteService.Object).Verifiable(); 
    var service = new Service(factory.Object); 

    //Act 
    service.Do(); 

    //Assert 
    remoteService.Verify(); 
    factory.Verify(); 
} 
関連する問題