David McLean
David McLean

Reputation: 1497

Moq multi interfaces

Background:

I have spun up a simple Proxy thing for my Wcf client based partly on examples found online and partly on my needs.

The usage for creating a client proxy as its known is:

WcfClientProxy<IServicecontract> clientProxy = 
                                 new WcfClientProxy<IServiceContract>();

WcfClientProxy has a method called Execute which takes : Expression<Func<TChannel, TResult>> or Expression<Action<TChannel>>.

What I'm trying to achieve:

I am trying to mock this using Moq so I can test the calls made to the service contract via the client.

So mock a call like this..

clientProxy.Execute(m=>m.DoSomeAction(5));

The problem:

The problem is that the mock does not work. I get this error:

" threw exception: System.NullReferenceException: Object reference not set to an instance of an object."

My test service contract is:

public interface ITestingServiceInterface : System.ServiceModel.IClientChannel
{
    string Version();
    VersionDetail VersionDetail();
    IList<VersionDetail> VersionDetails();
    void DoSomeDelete(int itemId);
}

The wcf client proxy interface:

public interface IWcfClientProxy<TChannel> where TChannel : ICommunicationObject
{
    bool ThrowOnException { get; set; }
    TResult Execute<TResult>(Expression<Func<TChannel, TResult>> operation);
    void Execute(Expression<Action<TChannel>> expression);
}

My attempted test and mock with setup..

private List<ProdItem> items;
private Mock<IWcfClientProxy<ITestingServiceInterface>> mockClientProxy;

[TestInitialize]
public void SettingUp()
{
    mockClientProxy = new Mock<IWcfClientProxy<ITestingServiceInterface>>();

    items = new List<ProdItem>();
    for( int i =0; i<10; i++){
        items.Add(new ProdItem { ProdItemId = i, LocalStock = i });
    }
}

[TestMethod]
public void SimpleTest()
{
    mockClientProxy.Setup(m => m.Execute(x => x.DoSomeDelete(It.IsAny<int>()))).Callback(RemoveItem);

    var client = mockClientProxy.Object;

    client.Execute(x => x.DoSomeDelete(4));

    Assert.AreEqual(9, items.Count);
}

public void RemoveItem()
{
    items.RemoveAt(items.Count - 1);
}

The error for this test is actually that the assert is wrong, it seems like the Callback is never being hit.

I'm sure I have just done something stupid.

Update: Showing an example of what I would like to be able to test if the above worked..

[TestMethod]
public void SimpleTest()
{
    mockClientProxy.Setup(m => m.Execute(x => x.DoSomeDelete(It.IsAny<int>()))).Callback(RemoveItem);

    var client = mockClientProxy.Object;

    var stockHelper = new StockHelper(client);

    stockHelper.DeleteItem(5);

    Assert.AreEqual(9, items.Count);
}

In the above I am testing the StockHelper Class that take a client proxy in its constructor through which it does its calls to WCF.

To test the StockHelper (or what ever) I need to be able to mock the client and its service calls. The above (1st) example demon-straights me having an issue trying to do this.

I hope that makes sense, please see that my end goal is not to test a mock.. that is just where I have got to trying to debug my issue.

Upvotes: 0

Views: 561

Answers (2)

The Vermilion Wizard
The Vermilion Wizard

Reputation: 5415

There's something weird going on in your mock setup. I think the matching parameters that you setup are restricted to the first layer of function calls. You might need to do something like:

mockClientProxy.Setup(m => m.Execute(It.IsAny<Expression<Action<TChannel>>>())).Callback(RemoveItem);

Moq works by implementing the methods on the interface of its argument, in this case it's the interface methods of IWcfClientProxy<ITestingServiceInterface>. So when you setup the method call to Execute, you need to setup the matching parameters for the arguments to Execute. What you've done in your code is to setup a match for that specific delegate function, which would never actually match anything because you don't store it and call Execute with it later.

Upvotes: 0

Sergey Berezovskiy
Sergey Berezovskiy

Reputation: 236308

As I can see from your code, you are testing mock. I don't see any real object you are testing. Mocks are used to stub dependencies of objects being tested. So, if some class Foo uses IWcfClientProxy then you provide mock of this proxy to class Foo. And verify that during Foo.Bar() execution method DoSomeDelete of dependency was called. That's the purpose of mocks.

[TestClass]
public class FooTests
{
   private Foo _foo;
   private Mock<IWcfClientProxy<ITestingServiceInterface>> _clientProxy;

   [TestInitialize]
   public void SettingUp()
   {
       _clientProxy = new Mock<IWcfClientProxy<ITestingServiceInterface>>();
       _foo = new Foo(_clientProxy.Object);
   }

   [TestMethod]
   public void SimpleTest()
   {
       // Act on object being tested
       _foo.Bar(5);

       // verify it executed correct method on dependency
       _clientProxy.Verify(cp => cp.Execute(x => x.DoSomeDelete(5)));
    }
}

Keep in mind, when testing Foo you should not care how _clientProxy is implemented.

Upvotes: 2

Related Questions