C# 犀牛嘲弄例外”;预期为1,实际为0;在工作代码中
我有一段关于MVVM的旧书中的代码,它是有效的,但使用Rhino Mocks的测试失败,并显示以下消息: 测试方法TestProject.UnitTest1.UpdateCustomer\u Always\u CallsUpdateWithCustomer引发异常: Rhino.Mocks.Exceptions.ExpectationViolationException:DataProvider.DoSomething(ConsoleApp.Customer);预期为1,实际为0 我提供了一个我认为相当的例子:C# 犀牛嘲弄例外”;预期为1,实际为0;在工作代码中,c#,rhino-mocks,C#,Rhino Mocks,我有一段关于MVVM的旧书中的代码,它是有效的,但使用Rhino Mocks的测试失败,并显示以下消息: 测试方法TestProject.UnitTest1.UpdateCustomer\u Always\u CallsUpdateWithCustomer引发异常: Rhino.Mocks.Exceptions.ExpectationViolationException:DataProvider.DoSomething(ConsoleApp.Customer);预期为1,实际为0 我提供了一个我
namespace ConsoleApp {
class Program { static void Main () { } }
public class Customer { public string ID { get; set; } }
public class DataProvider {
public virtual Customer GetCustomer (string id) => new Customer ();
public virtual void DoSomething (Customer customer) { }
}
public class ViewModel {
DataProvider _dataProvider;
Customer _customer;
public ViewModel (DataProvider dataProvider, string id) {
_dataProvider = dataProvider;
_customer = new Customer { ID = id };
}
public void DoSomething () => _dataProvider.DoSomething (_customer);
}
}
以及失败的测试
namespace TestProject {
[TestClass]
public class UnitTest1 {
[TestMethod]
public void UpdateCustomer_Always_CallsUpdateWithCustomer () {
DataProvider dataProviderMock = MockRepository.GenerateMock<DataProvider> ();
Customer expectedCustomer = new Customer ();
dataProviderMock.Stub (u => u.GetCustomer (Arg<string>.Is.Anything)).Return (expectedCustomer);
ViewModel target = new ViewModel (dataProviderMock, string.Empty);
target.DoSomething ();
dataProviderMock.AssertWasCalled (d => d.DoSomething (expectedCustomer));
}
}
}
名称空间测试项目{
[测试类]
公共类UnitTest1{
[测试方法]
public void UpdateCustomer\u Always\u CallsUpdateWithCustomer(){
DataProvider dataProviderMock=MockRepository.GenerateMock();
客户期望客户=新客户();
dataProviderMock.Stub(u=>u.GetCustomer(Arg.Is.Anything)).Return(expectedCustomer);
ViewModel目标=新的ViewModel(DataProviderLock,string.Empty);
target.DoSomething();
调用DataProviderLock.Assertwas(d=>d.DoSomething(expectedCustomer));
}
}
}
我读了几篇关于这个结果的帖子,例如和,但这对我没有帮助。我读了一本似乎很有趣的书:
当使用对象参数调用存根方法时,通常会出现此错误
我在测试和测试代码中构建的对象是在调用该方法之前构建的
虽然这可能是犀牛模仿失败的原因,但它似乎是一个bug
我的问题是:我的测试中是否有错误,Rhino Mocks中是否有错误,或者我的代码是否有问题?测试存根
DataProvider.GetCustomer
,以返回要在断言中使用的预期客户实例,但示例视图模型不调用DataProvider.GetCustomer
它正在使用构造函数中初始化的
//...
public ViewModel (DataProvider dataProvider, string id) {
_dataProvider = dataProvider;
_customer = new Customer { ID = id };
}
//...
因此,在给出的示例中,测试引发的异常是准确的
这是因为在执行测试时,视图模型使用的实际实例将不是断言中使用的实例
//...
dataProviderMock.AssertWasCalled (d => d.DoSomething (expectedCustomer));
为了使测试根据其安排按预期运行,视图模型实际上必须进行重构,以与初始化客户
比如说
public class ViewModel {
DataProvider _dataProvider;
string id;
public ViewModel (DataProvider dataProvider, string id) {
_dataProvider = dataProvider;
this.id = id;
}
public void DoSomething () {
Customer customer = _dataProvider.GetCustomer(id);
_dataProvider.DoSomething (_customer);
}
}
测试还应该更明确地说明它要测试什么
[TestClass]
public class UnitTest1 {
[TestMethod]
public void UpdateCustomer_Always_CallsUpdateWithCustomer () {
//Arrange
DataProvider dataProviderMock = MockRepository.GenerateMock<DataProvider> ();
string id = "FakeId";
Customer expectedCustomer = new Customer { ID = id };
dataProviderMock.Stub (u => u.GetCustomer (id))
.Return (expectedCustomer);
ViewModel target = new ViewModel (dataProviderMock, id);
//Act
target.DoSomething ();
//Assert
dataProviderMock.AssertWasCalled (d => d.DoSomething (expectedCustomer));
}
}
[TestClass]
公共类UnitTest1{
[测试方法]
public void UpdateCustomer\u Always\u CallsUpdateWithCustomer(){
//安排
DataProvider dataProviderMock=MockRepository.GenerateMock();
字符串id=“FakeId”;
客户期望客户=新客户{ID=ID};
dataProviderLock.Stub(u=>u.GetCustomer(id))
.退货(预期客户);
ViewModel目标=新的ViewModel(dataProviderMock,id);
//表演
target.DoSomething();
//断言
调用DataProviderLock.Assertwas(d=>d.DoSomething(expectedCustomer));
}
}
或者,如果视图模型符合预期,那么测试需要以不同的方式声明其期望
[TestClass]
public class UnitTest1 {
[TestMethod]
public void UpdateCustomer_Always_CallsUpdateWithCustomer () {
//Arrange
DataProvider dataProviderMock = MockRepository.GenerateMock<DataProvider> ();
string id = "FakeId";
ViewModel target = new ViewModel (dataProviderMock, id);
//Act
target.DoSomething ();
//Assert
dataProviderMock
.AssertWasCalled (d => d.DoSomething (Arg<Customer>.Matches(c => c.ID == id));
}
}
[TestClass]
公共类UnitTest1{
[测试方法]
public void UpdateCustomer\u Always\u CallsUpdateWithCustomer(){
//安排
DataProvider dataProviderMock=MockRepository.GenerateMock();
字符串id=“FakeId”;
ViewModel目标=新的ViewModel(dataProviderMock,id);
//表演
target.DoSomething();
//断言
dataProviderMock
.AssertWasCalled(d=>d.DoSomething(Arg.Matches(c=>c.ID==ID));
}
}
请注意,断言中使用的委托用于验证预期参数的特征,而不是在调用该参数时传递的特定实例。您可能需要提供……仅显示一些代码,很难看到整体情况。@AlexeiLevenkov:您说得对,完成。@mins您的示例视图模型没有调用
DataProvider.GetCustomer
。它使用的是构造函数中初始化的异常。因此,给定所示示例,测试引发的异常是准确的。“测试只是检查DataProvider.DoSomething是用某个对象调用的”据我所知,不是文章中的代码所显示的……而是“DoSomething
正是使用expectedCustomer
调用的。”“示例视图模型没有调用DataProvider.GetCustomer。它使用构造函数中初始化的一个”DataProvider.GetCustomer>被模拟覆盖以返回它自己的对象:dataProviderMock.Stub(u=>u.GetCustomer(Arg.Is.Anything)).Return(expectedCustomer)
。我可以更新我的示例,但这不会改变错误(我可能错了)在您的示例中,@minsGetCustomer
从未被使用。您正在viewmodel构造函数中手动创建实例。您的答案是正确的,因为我的问题,所以我接受它。我问题中的错误代码不能代表产生错误的代码,因此答案无法重复使用。如果可以简化,我将发布一个新问题请用一个好的示例演示我的代码。@mins已理解。请确保您的示例准确地反映了实际问题。