开发者

How can I use Rhino Mocks to inspect what values were passed to a method

开发者 https://www.devze.com 2023-01-07 07:23 出处:网络
I\'m new to mocking, and I\'m having a hard time solving an issue with UnitTesting. Say I have this code:

I'm new to mocking, and I'm having a hard time solving an issue with UnitTesting.

Say I have this code:

public class myClass{

    private IDoStuff _doer;

    public myClass(IDoStuff doer){
        _doer = doer;
    }

    public void Go(SomeClass object){

        //do some crazy stuff to the object

        _doer.DoStuff(object) //this method is  void too
    }
}

Ok, so I want to UNIT test the Go method. I don't care what the _doer object does to the object once is gets it.

HOWEVER, I do want to inspect what the _doer object has received.

in PSEUDO code I want to achieve this:

[Test]
public void MyTest()
{
    IDoStuff doer = Mocker.Mock<IDoStuff>();
    Guid id = Guid.NewGuid();

    //test Go method
    new MyClass(doer).Go(new SomeClass(){id = id});

    Assert.AreEqual(id,MockingFramework.Method(DoStuff).GetReceived<SomeClass>().id);
}

Is this possible using Rhino, and if so, how do I achieve it?

开发者_C百科cheers


With the new Arrange/Act/Assert syntax:

[Test]
public void MyTest()
{
    // arrange
    IDoStuff doer = MockRepository.GenerateStub<IDoStuff>();
    MyClass myClass = new Myclass(doer);
    Guid id = Guid.NewGuid();

    // act
    myClass.Go(new SomeClass(){id = id});

    // assert
    doer.AssertWasCalled(x => x.DoStuff(
        Arg<Someclass>.Matches(y => y.id == id)));
}


All of these answers provide various ways to do what you want and all of them work. There's one additional thing to be aware of. If you need to get really "low level" and check out arguments passed to any stubbed/mocked method, you can use GetArgumentsForCallsMadeOn.

It's a little messy as it returns object[][]. You use it like this (assuming you stubbed stubber.InsertData to accept null):

var args = stubber.GetArgumentsForCallsMadeOn(s => s.InsertData(null));

args[0] is an array of parameters passed to InsertData the first time it was called.

args[1] is an array of parameters passed to InsertData the second time it was called.

etc...

So if you wanted to see the integer value passed as the second parameter of the first invocation of some method you could:

var check = (int) args[0][1];

Again, I'd recommend one of the previous methods, but this is available if you need to get really down and dirty to check out arguments.


I think what you have is good so it'd be:

IDoStuff doer = MockRepository.GenerateMock<IDoStuff>();

then set up the expectation via:

doer.Expect(() => DoStuff(id));

then at the end:

doer.VerifyAllExpectations();

EDITED from Lee's answers to note that you can also do stuff like:

doer.Expect(d => d.DoStuff(Arg<int>.Is.GreaterThan(5))

or

doer.Expect(d => d.DoStuff(Arg<CustomObject>.Matches(x => x.CustomProperty == "Beef")));

or similar tests when you don't want exact reference comparisons by using the Arg and Arg objects.


Only a suggestion:

both solution from Wim Coenen and Patrick Steele are correct but, for first solution, very fast when there is only one parameter, there are an incorrect error message when test fails.

This is a message for my function with two parameters:

IProductChecker.MustPublish(equal to 2, equal to 123X); Expected #1, Actual #0.

Now, which of the two parameters is wrong? And what about if parameters were more?

I've prepared test with this code:

//ARRANGE
const string CLASSCODE = "ABC";
const string SUBCLASSCODE = "123X";
var expected = new [] {CLASSCODE, SUBCLASSCODE};

//ACT
SUT.CallMyFunction(chkMock);
var actual = chkMock.GetArgumentsForCallsMadeOn(m => m.MustPublish(null, null))[0];

//Assert
CollectionAssert.AreEqual(expected, actual);
//instead of
//chkMock.AssertWasCalled(m => m.MustPublish(Arg<string>.Is.Equal("2"), Arg<string>.Is.Equal(SUBCLASSCODE)));

So, in this case the message is:

CollectionAssert.AreEqual failed. (Element at index 0 do not match.)

Hi


If you just want to test that the MyClass instance passes its parameter to doer.Go then you can just set up an expectation:

SomeClass obj = new SomeClass { id = id };

doer.Expect(d => d.DoStuff(obj));

//test go method
new MyClass(doer).Go(obj);

doer.VerifyAllExpectations();

However if you want to check that it passes some possibly different object with some particular value for a property, then you can use a constraint:

doer.Expect(d => d.DoStuff(null))
    .IgnoreArguments()
    .Constraints(Property.Value("Id", expectedId));
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号