如何使用Rhino Mocks检查传递给方法的值

时间:2010-07-12 13:36:55

标签: c# unit-testing mocking rhino-mocks

我是嘲笑的新手,我很难解决UnitTesting的问题。

说我有这段代码:

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
    }
}

好的,所以我想UNIT测试Go方法。我不关心_doer对象一旦得到它就对对象做了什么。

但是,我确实想检查_doer对象收到了什么。

在PSEUDO代码中我想实现这个目标:

[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);
}

这是否可以使用Rhino,如果可以,我该如何实现呢?

欢呼声

5 个答案:

答案 0 :(得分:23)

使用新的Arrange / Act / Assert语法:

[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)));
}

答案 1 :(得分:7)

所有这些答案提供了各种方法来完成您想要的并且所有这些方法都有效。还有一件事需要注意。如果您需要获得真正的“低级别”并检查传递给任何存根/模拟方法的参数,则可以使用GetArgumentsForCallsMadeOn

它返回object [] []时有点乱。你像这样使用它(假设你将stubber.InsertData存根为接受null):

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

args [0]是第一次调用时传递给InsertData的参数数组。

args [1]是第二次调用时传递给InsertData的参数数组。

等...

所以如果你想看到传递的整数值作为第一次调用某个方法的第二个参数,你可以:

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

同样,我建议使用以前的方法之一,但是如果您需要真正关闭并查看参数,这是可用的。

答案 2 :(得分:5)

我认为你所拥有的是好的所以它是:

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

然后通过以下方式设置期望:

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

然后在最后:

doer.VerifyAllExpectations();

来自Lee的回答,请注意你也可以这样做:

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

doer.Expect(d => d.DoStuff(Arg<CustomObject>.Matches(x => x.CustomProperty == "Beef")));
当您不希望使用Arg和Arg对象进行精确的参考比较时,

或类似的测试。

答案 3 :(得分:3)

只有一个建议:

来自Wim CoenenPatrick Steele的解决方案都是正确的,但是,对于第一个解决方案,当只有一个参数时非常快,当测试失败时会出现错误的错误消息。

这是我的函数的消息,有两个参数:

  

IProductChecker.MustPublish(等于2,等于123X);预期#1,实际#0。

现在,这两个参数中的哪一个是错误的?如果参数更多呢?

我已准备好使用此代码进行测试:

//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)));

因此,在这种情况下,消息是:

  

CollectionAssert.AreEqual失败。 (索引0处的元素不匹配。)

你好

答案 4 :(得分:1)

如果您只想测试MyClass实例将其参数传递给doer.Go,那么您可以设置一个期望:

SomeClass obj = new SomeClass { id = id };

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

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

doer.VerifyAllExpectations();

但是,如果要检查它是否通过某个可能不同的对象以及属性的某个特定值,则可以使用约束:

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