How to specify that Arg<T>.Matches() shouldn't return default(T)

279 views Asked by At

I have a little problem with Rhino Mocks.

I have an abstract class with a method that expects an object (in the sample below a string). The method checks if the argument is null.

public abstract class Foo
{
    public void DoSomething(string bar)
    {
        if (bar == null)
        {
            throw new ArgumentNullException("bar");
        }
    }
}

I have another class, which uses Foo:

public class Baz
{
    private readonly Foo foo;

    public Baz(Foo foo)
    {
        this.foo = foo;
    }

    public void DoWork(string s)
    {
        s = "xxx" + s;
        this.foo.DoSomething(s);
    }
}

I want to make a unit test and check if DoSomething of class Foo is called with the correct argument. I used Arg<T>.Matches() for this.

    [Test]
    public void TestMethod()
    {
        var fooMock = MockRepository.GenerateMock<Foo>();
        var objectUnderTest = new Baz(fooMock);

        fooMock.Expect(x => x.DoSomething(Arg<string>.Matches(Text.StartsWith("xxx"))))
            .Repeat.Once();

        objectUnderTest.DoWork("hello");

        fooMock.VerifyAllExpectations();
    }

Now, when I try to run this test, an ArgumentNullException at the Expect(...) is raised. I looked at the code of Rhino Mocks and discovered that the Match()-Method always returns default(T), which is null for a string (and every other class). So the check in DoSomething() raises an ArgumentNullException.

I know, that I could extract an interface for Foo and create a mock of that interface, so there is no null check. But I want to know if that problem is solvable with Rhino Mocks by leaving the code like it is (except the unit test of course ;-) ).

1

There are 1 answers

0
Alexander Stepaniuk On

Problem is not solvable by changing test code only. The code under test is written in non test-friendly way.

The reason is that Rhino Mock requires mocked/stubbed method to be overridable. I.e. DoSomething() should either be interface method (as you described in question) or be virtual method.
If it was overridable then the real method DoSomething() wouldn't be triggered within Expect() call at all.

Both options could work but both require code under test change.

If this is possible to modify the code under test then in my opinion usage interface like IFoo instead of abstract class Foo is the preferrable way. As this is how dependency injection should be implemented properly.