我从一本关于MVVM的旧书中获得了一段代码,该代码可以正常工作,但是使用Rhino Mocks进行的测试失败,并显示以下消息:
测试方法TestProject.UnitTest1.UpdateCustomer_Always_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));
}
}
}
我阅读了有关此结果的几篇文章,例如1和2,但这对我没有帮助。我读了this answer,这似乎很有趣:
当使用对象参数调用存根方法时,通常会出现此错误 我在测试和测试代码中构建的对象是在调用该方法之前构建的。
虽然这可能是Rhino Mocks失败的原因,但似乎是一个错误。
我的问题是:我的测试是否有问题,Rhino Mocks中存在错误,或者我的代码是否有问题?
示例视图模型不调用DataProvider.GetCustomer
。
它使用在构造函数中初始化的那个。
//...
_customer = new Customer { ID = id };
//...
因此,在给出的示例中,测试抛出的异常是准确的。
为了使测试根据其排列方式表现出预期的效果,实际上应该重构视图模型以与初始化Customer
脱钩
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));
}
}