19

I'm new to Moq and learning.

I need to test that a method returns the value expected. I have put together a noddy example to explain my problem. This fails miserably with:

"ArgumentException: Expression is not a method invocation: c => (c.DoSomething("Jo", "Blog", 1) = "OK")"

Can you correct what I am doing wrong?

[TestFixtureAttribute, CategoryAttribute("Customer")]
public class Can_test_a_customer
{
    [TestAttribute]
    public void Can_do_something()
    {
        var customerMock = new Mock<ICustomer>();

        customerMock.Setup(c => c.DoSomething("Jo", "Blog", 1)).Returns("OK");

        customerMock.Verify(c => c.DoSomething("Jo", "Blog", 1)=="OK");
    }
}

public interface ICustomer
{
    string DoSomething(string name, string surname, int age);
}

public class Customer : ICustomer
{
    public string DoSomething(string name, string surname, int age)
    {
        return "OK";
    }
}

In a nutshell: if I wanted to test a method like the one above, and I know that I am expecting back an "OK", how would I write it using Moq?

Thanks for any suggestions.

Gishu
  • 134,492
  • 47
  • 225
  • 308

3 Answers3

19
  1. You need a test subject that interacts with mock objects (unless you're writing a learner test for Moq.) I wrote up a simple one below
  2. You setup expectations on the mock object, specifying the exact arguments (strict - if you wish to ofcourse, else use Is.Any<string> to accept any string) and specify return values if any
  3. Your test subject (as part of the Act step of the test) will call onto your mock
  4. You assert the test subject behaved as required. The return value from the mock methods will be used by the test subject - verify it via the test subject's public interface.
  5. You also verify that all expectations that you specified were met - all methods that you expected to be called were in fact called.

.

[TestFixture]
public class Can_test_a_customer
{
  [Test]
  public void Can_do_something()
  {
    //arrange
    var customerMock = new Moq.Mock<ICustomer>();
    customerMock.Setup(c => c.DoSomething( Moq.It.Is<string>(name => name == "Jo"),
         Moq.It.Is<string>(surname => surname == "Blog"),
         Moq.It.Is<int>(age => age == 1)))
       .Returns("OK");

    //act
    var result = TestSubject.QueryCustomer(customerMock.Object);

    //assert
    Assert.AreEqual("OK", result, "Should have got an 'OK' from the customer");
    customerMock.VerifyAll();
  }
}

class TestSubject
{
  public static string QueryCustomer(ICustomer customer)
  {
    return customer.DoSomething("Jo", "Blog", 1);
  }
}
Gishu
  • 134,492
  • 47
  • 225
  • 308
  • 1
    Exactly. His test has no test subject, which has lead to the confusion. You test a test subject, not a mock. – Anderson Imes Sep 18 '09 at 19:11
  • I am learning too, I think that I have my head wrapped around this, would you confirm please. In this example `DoSomething` could return `jabberwocky` but because your `//arrange .Setup` is told to `.Return("OK")` that is the assertion. I understand the test is to make sure that `TestSubject` performs as expected, and there is not a test on `Customer` here. If that is case, why assert the return value from `Customer` and not just `.Returns("SUCCESS")` or some other generic string to verify that `TestSubject` completed succesfully? – JabberwockyDecompiler Dec 23 '15 at 19:08
  • @JabberwockyDecompiler - it was just a sample test where the output depends on a collaborator (mocked).. e.g customer could return "Sam" and the method/class under test could return "Hello Sam!". To test this: you would need to setup the mock to return "Sam" in the test. – Gishu Jan 11 '16 at 10:05
  • @Gishu I think that we are on the same page, the mock determines the return value to test, not the method. Meaning that as long as `DoSomething` performs w/o error the `Assert.AreEqual` is a comparison to the string value in the mock `.Returns("OK")` and not an actual value returned from `DoSomething`, `return "OK";`. I am attempting to make the switch from `Integration Testing` to `Unit Testing` and with `IT` the test values are passed into the method and the method does an actual execution. The OP has `DoSomething` return `OK` I wanted to confirm that is different from the mock `OK`. Thanks. – JabberwockyDecompiler Jan 11 '16 at 17:44
12

Mock<T>.Verify doesn't return the value that the method call returned, so you can't just compare it to the expected value using "==".

In fact, there is no overload of Verify that returns anything, because you should never need to verify that a mocked method returns a specific value. After all, you were responsible for setting it up to return that value in the first place! Return values of mocked methods are there to be used by the code you're testing - you're not testing the mocks.

Use Verify to confirm that the method was called with the arguments you expected, or that a property was assigned a value you expected. The return values of mocked methods and properties aren't important by the time you get to the "assert" phase of your test.

Matt Hamilton
  • 200,371
  • 61
  • 386
  • 320
2

You are doing the same thing this guy was doing here: How to Verify another method in the class was called using Moq

You are mocking what you are testing. This doesn't make sense. Use of Mocks is for isolation. Your Can_Do_Something test will always pass. No matter what. This is not a good test.

Take a closer look at Gishu's test or the test I proposed in the linked SO question.

Community
  • 1
  • 1
Anderson Imes
  • 25,500
  • 4
  • 67
  • 82
  • Hi, you are absolutely right ,I am new in the world of mocking So is it correct to say that Mocking a method is just to verify that the method was called or a property was set not to verify what the method returns.Is this correct? –  Sep 19 '09 at 05:04
  • 1
    A mock is designed to verify an external method AND isolate the code you are *actually* testing. For example, if your class tried to access a database, you would mock your data acccess class so that not only did it return consistent results, but so your test didn't require a database to run. You are isolating the class you are testing from other changes to other classes you might make. – Anderson Imes Sep 19 '09 at 13:33