2

I have a method that calls another method of a mocked object with a parameter that is calculated according to the parameters that I passed to my tested function.
How do I verify that the method my tested method is calling is called correctly.
I am using Moq.

EDIT:
As none of you get what I mean (or as I do not understand the fact that you guys solved the problem for me) I'll be more concreate.
I have the following method signature:

IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state);

Inside it should instantiate a SocketAsyncEventArgs object and call it's SetBuffer method with the right SocketAsyncEventArgs.
The SocketAsyncEventArgs is an implementation detail, but it is however the only way to implement the feature I am after so I have to check if it's SetBuffer method is called correctly. How do I make sure that the BeginWrite() implementation does actually call SetBuffer with the right parameters?

Edit 2:
Here's some code to clarify what I mean:

public IAsyncResult BeginWrite(byte[] buffer, int offset, int size, AsyncCallback callback, object state)
{
    // No mocking can be done here
    SocketAsyncEventArgs args = new SocketAsyncEventArgs
                                    {
                                        // Proper initialization. Should be verified as well.
                                    };
    args.SetBuffer(buffer, offset, size);
    Client.SendAsync(args);
}
the_drow
  • 18,571
  • 25
  • 126
  • 193

3 Answers3

7

You can test whether the method is being called via the Verify method. If the called method does not return anything then you dont need a Setup. I prefer this than the Setup or Expect/VerifyAll approach as it is more AAA.

[Test]
public void ShoudlCallMockMethod()
{
    var mocked = new Mock<IDoStuff>();

    var target = new ClassToTest(mocked.Object);
    target.DoStuff();

    mocked.Verify(x => x.CallMyMethod(It.IsAny<string>());
}

here it expects that a call to CallMyMethod with any argument. If you know the exact argument passed in and want to check that then do

mocked.Verify(x => x.CallMyMethod("exactstring"));

if you want more complex matching of what was passed in (useful for complex objects with many araguments) then have a look at another answer I did with using a matcher.

You can also add Times.AtMostOnce() if you want to ensure it gets called only once

[Edit]

Based on your edits and comments you do not need to mock the args object but if you still want to verify that the parameters are set then you can verify on the Client.SendAsync method, provided that can be mocked (which I would suggest you should aim towards if you have not already done so). The link I provided about matchers should help with that.

As for you question in your comment over the past few years there has been a shift from Record/Replay-Verify > Expect/Setup-Verify > [Setup]-Verify. It can be down to the mocking technology but mostly due to the introduction of lambda expressions in c#3.5 and then the move to AAA. What you really want is small readable tests that follow the AAA principle so having Expect/Setup-VerifyAll is really having the Assert in the Arrange phase (you have to look back to see what is being verified). So unless the mocked method needs to return something then you don't need the Setup, just verify that the method was called in the Assert phase.

Community
  • 1
  • 1
aqwert
  • 10,559
  • 2
  • 41
  • 61
  • +1 That is nicer than mine - I always forget that they refactored the api to allow that, so default to using setup. – David Hall Apr 20 '11 at 21:03
  • @the_drow Can you provide some code as to the class that has the SetBuffer method. Is this a mocked class? How does the BeginWrite method use it? – aqwert Apr 21 '11 at 01:38
  • Code provided. Now that I think about it I am not testing SetBuffer so it doesn't matter how it behaves. It only matters that the properties it exposes (Buffer, Offset and Count) are equal to what I am setting in my method. What's the difference between the Verify approach and the Setup and VerifyAll approach? – the_drow Apr 21 '11 at 02:35
1

I believe it will verify that the argument you pass in when calling Setup is equal to the argument passed in by the real code.

The QuickStart guide has examples of more interesting constraints. Unfortunately the links to the external API guide are failing at the moment :(

EDIT: I suspect you want something like:

mock.Setup(foo => foo.SendAsync(It.Is<AsyncCallback>(x => 
           {
               // Whatever you need to test here
               return x.Buffer.Length == 15 && 
                   x.Offset = 10 &&
                   x.Count = 5;
           }));
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • @the_drow: It sounds like you want a very custom matcher then... I don't know the Moq API, but basically it looks like you want the `It.Is` method, which should check the properties of the argument. See my edit. – Jon Skeet Apr 21 '11 at 05:29
  • @JonSkeet: Well, the silverlight API is giving me a massive headache. So yeh, I pretty much have to do stuff like this to make things work. Not to mention the amount adapters I need to write to wrap classes into a mockable state (have an interface). And by looking at the code, you are completely off. – the_drow Apr 21 '11 at 06:06
  • @the_drow: I'm not sure what you mean by being "completely off" - are you mocking SendAsync or not? If you're not, what *are* you trying to mock? – Jon Skeet Apr 21 '11 at 07:32
  • @JonSkeet: SendAsync should just be a stub. I am trying to check what parameters are passed to SendAsync. The boolean return value indicates if the operation was completed synchronously or asynchronously so yes, I can do what you suggested but it abuses the API. – the_drow Apr 21 '11 at 12:21
  • @the_drow: A stub or a mock? I don't see what's abusing the API here. You're just providing a matcher routine for the argument, that's all. That's what that area of the API is there for. Of course, you don't have to inline it - you could easily put that into a different method if you wanted. – Jon Skeet Apr 21 '11 at 12:57
  • @JonSkeet: Ok, I'll rephrase the purpose here so you'll know what I'm doing. As I mentioned to you on twitter I am porting NetworkStream to silverlight. I am just adapting the socket methods to use the async method pattern. To send a buffer over a silverlight socket I have to prepare a SocketAsyncEventArgs and pass it to the socket's SendAsync method. What you are offering is to use the boolean return value of the SendAsync method to verify that the buffer was set correctly which is abusing the API since it's used to indicate wheter the operation was completed synchronously or not. – the_drow Apr 21 '11 at 14:05
  • @JonSkeet: Continued... This is what I mean by abusing the API. The return value should indicate something completely different. Now for this kind of testing the **socket** should be mocked and the **SendAsync** method should be stubbed as I don't care about it's return value. What should be tested is the SocketAsyncEventArgs that are passed to SendAsync. If the buffer was set correctly than the properties should be the same as the input of the BeginWrite method. Am I clear now? – the_drow Apr 21 '11 at 14:08
  • @the_drow: No, I'm *not* suggesting that at all. I'm suggesting you use `It.Is` which I believe should throw an exception if the argument isn't matched. I suspect you've misunderstood my answer - have another look. – Jon Skeet Apr 21 '11 at 14:23
  • @JonSkeet: Now I'm having a problem: ISocket.SendAsync(System.Net.Sockets.SocketAsyncEventArgs) invocation failed with mock behavior Strict. All invocations on the mock must have a corresponding setup. for this code: mockedSocket.Setup(socket => socket.SendAsync(It.Is(args => Args.Buffer == args.Buffer && Args.Count == args.Count && Args.Offset == args.Offset))); – the_drow Apr 21 '11 at 14:44
  • @the_drow: What is Args? It looks like you're comparing one byte array with another by comparing references. That sounds like a bad idea to me... you may want a helper method to compare their *contents*. For the moment, if you just compare the offset and count, does that work? If so, this shows that the general approach is working correctly :) – Jon Skeet Apr 21 '11 at 14:54
  • @JonSkeet: Figured it out a second before I checked here. Note that verify is still the best appraoch here. – the_drow Apr 21 '11 at 14:59
  • @the_drow: Why do you say that? You're specifying in the expectation exactly what constraints the argument should conform to... and that means the test will fail *at exactly the point where the production code is making the wrong call* unless I've mistaken something. Also, with Verify, how do you set what the return value should be? – Jon Skeet Apr 21 '11 at 15:06
  • @JonSkeet See @aqwert edit. Also the fact that the operation completed synchronously or not **does not matter to me** in this case. I just need to check that the correct buffer was set. – the_drow Apr 21 '11 at 16:27
  • @the_drow: I think we'll just have to agree to differ. – Jon Skeet Apr 21 '11 at 17:07
0

The test below fails due to the setup expectation of the parameter named value being passed as "expected" not being met. I think this is what you are after?

[TestClass]
public class MyTests
{
    [TestMethod]
    public void TestParameterExpectation()
    {
        var mock = new Mock<IInterface>();
        mock.Setup(x => x.CallMe("expected"));

        CallIt("not expected", mock.Object);

        mock.VerifyAll();

    }

    public void CallIt(string value, IInterface callit)
    {
        callit.CallMe(value);
    }

}

public interface IInterface
{
    void CallMe(string value);
}
David Hall
  • 32,624
  • 10
  • 90
  • 127