RhinoMock AssertWas对相同的对象进行了两次调用

时间:2014-05-10 12:39:20

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

我有一个方法,它将对象添加到数据库,处理该对象,然后在处理成功时更新数据库中的同一对象。处理是系统(支付)的一个非常关键的部分,所以我想确保如果系统在处理过程中崩溃/掉电,我们仍然有初始添加,然后我们可以再次处理。

public void CreateAndProcess(){
        var myObj= new myObj
        {
            // Set up myObj here
        };

        db.Add(myObj);
        db.SaveChanges();

        // Process and update myObj here

        db.Update(myObj);
        db.SaveChanges();
}

然后我想对CreateAndProcess方法进行单元测试,以确保使用包含正确值的myObj调用Add和Update方法。

// addedObj and updatedObj are objects I define in my test that should match.    
_store.AssertWasCalled(store => store.Add(Arg<myObj>.Matches(mo => Equal(mo, addedObj))), 
                       option => option.Repeat.Once()); // Initial add to db
_store.AssertWasCalled(store => store.Update(Arg<myObj>.Matches(mo => Equal(mo, updatedObj))), 
                       option => option.Repeat.Once()); // Update in db after processed

private static bool Equal(myObj s1, myObj s2)
{
   // Used to match a subset of properties I care about
   Assert.That(s1.myProp, Is.EqualTo(s2.myProp), "Unexpected argument");
   return true;
}

问题是第一个AssertWasCalled在更新后使用对象的最终状态,而不是在调用Add()函数时它的值。

如何在最初添加到数据库时测试myObj的状态?

谢谢,

1 个答案:

答案 0 :(得分:1)

Rhino Mock在调用stubbed方法时提供Do()处理程序来访问存根方法参数。
因此,可以为Add(MyObj)方法编写自定义处理程序,该方法可以存储传递的myObj参数的必要字段。然后就可以对存储的字段运行断言。

以下是一个例子:

string actualMyPropOnAdd = null;

_store
    .Stub(s => s.Add(Arg<MyObj>.Is.Anything))
    .Do((Action<MyObj>)(myObj =>
    {
        // save the necessary properties to validate them later
        actualMyPropOnAdd = myObj.myProp;
    }));

// call CreateAndProcess() here

// validate saved properties:
Assert.That(actualMyPropOnAdd, Is.EqualTo(expectedMyPropOnAdd));

另外,我建议关注one asser per test rule并编写另一个单独的测试来验证传递给Update()方法的参数是否正确。