1

I'm just starting to use RhinoMocks. Now I'm wondering what test cases I should write. I want to assert that a method is only being called once, with specific arguments.

Lets start with my interfaces.

public class BarQueryParameters
{
    public int Id { get; set; }
    public List<string> Categories { get; set; }
}

public interface IBar
{
    void CalFoo(BarQueryParameters parameters);
}

public class FooQueryParameters
{
    public string Id { get; set; }
    public List<string> Types { get; set; }
}

public interface IFoo
{
    IEnumerable<string> CallMe(FooQueryParameters parameters);
}

Then we have the Bar class that implements IBar and calls IFoo's CallMe method:

public class Bar : IBar
{
    private readonly IFoo _foo;

    public Bar(IFoo foo)
    {
        _foo = foo;
    }

    public void CalFoo(BarQueryParameters parameters)
    {
        List<string> result = _foo.CallMe(new FooQueryParameters
        {
            Id = parameters.Id.ToString(),
            Types = parameters.Categories.ToList()
        }).ToList();
        Console.WriteLine(result.Count);
    }
}

I want to test that if CallFoo is called with Id = 1, Categories = new List<string> {"One", "Two"}, this results in a call to IFoo.CallMe. I want to make sure the FooQueryParameters are what I expect.

At first I wrote:

    [TestMethod]
    public void TestFooBarConversion2()
    {
        IFoo mockedFoo = MockRepository.GenerateMock<IFoo>();
        mockedFoo.Expect(foo => foo.CallMe(Arg<FooQueryParameters>
            .Matches(p => p.Id.Equals("1") && p.Types.SequenceEqual(new List<string> {"One", "Two"}))))
            .Repeat.Once();

        IBar bar = new Bar(mockedFoo);
        bar.CalFoo(new BarQueryParameters {Id = 1, Categories = new List<string> {"One", "Two"}});

        mockedFoo.VerifyAllExpectations();
    }

That won't work as Bar expects a result from its call to Foo.CallMe (it tries to ToList() the result). Currently the test will result in a NullReferenceException. So, I'd have to also make sure my mocked method returns something like a new List<string>().

Still not there though. What would happen if Bar contains a programming error and calls CallMe with incorrect arguments? In that case, the unit test will fail, but not on the VerifyAllExpectations. It will again run into a NullReferenceException.

So now I'd say my mocked CallMe should always return a new List<string>(). But I'd still want to make sure it is being called once with the expected arguments. I also want to make sure it is not being called with any other arguments.

Then I'd get:

    [TestMethod]
    public void TestFooBarConversion()
    {
        IFoo mockedFoo = MockRepository.GenerateMock<IFoo>();
        mockedFoo.Expect(foo => foo.CallMe(Arg<FooQueryParameters>
            .Matches(p => p.Id.Equals("1") && p.Types.SequenceEqual(new List<string> {"One", "Two"}))))
            .Repeat.Once()
            .Return(new List<string>());
        mockedFoo.Expect(foo => foo.CallMe(Arg<FooQueryParameters>
            .Matches(p => !p.Id.Equals("1") || !p.Types.SequenceEqual(new List<string> {"One", "Two"}))))
            .Repeat.Never()
            .Return(new List<string>());

        IBar bar = new Bar(mockedFoo);
        bar.CalFoo(new BarQueryParameters {Id = 1, Categories = new List<string> {"One", "Two"}});

        mockedFoo.VerifyAllExpectations();
    }

This doesn't seem right to me.

  1. Is there a simpler way to do this?
  2. Should I not care if the method is also called with other arguments?
  3. Should I not care if the test fails on a NullReferenceException?
  • Might be simpler to turn the second Expect into one that just checks it was called at all, exactly once. Combined with the first, that's equivalent to checking that it isn't called with other arguments – Ben Aaronson May 29 '15 at 10:20
  • If I do that, the unit test fails on the second expectation. It looks like it considers the single call to CallMe to satisfy both lambda's. But if I change that second one to expect Once, it also fails on the second expectation. (I assume you mean mockedFoo.Expect(foo => foo.CallMe(Arg<FooQueryParameters>.Is.Anything)).Repeat.Never()) – comecme May 30 '15 at 16:58
  • No, I meant what you wrote in that comment, except with Repeat.Once() instead of Repeat.Never(). – Ben Aaronson May 30 '15 at 19:18
  • 1
    As I said, when I change it to Repeat.Never() it also fails (Expected #1, Actual #0). Wit Repeat.Once() it fails with Expected #0, Actual #1. Almost seems like a bug in RhinoMocks? – comecme Jun 1 '15 at 5:47
  • Seems weird if that's all you're changing. Unfortunately beyond my level of knowledge of RhinoMocks. – Ben Aaronson Jun 1 '15 at 11:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.