播种存储库 Rhino Mocks
我即将开始我的第一次 C# 测试驱动开发之旅。首先,我使用 MSTest 和 Rhino.Mocks。我正在尝试针对我的 ICustomerRepository
编写第一个单元测试。为每个测试方法新建一个Customer
似乎很乏味。在 ruby-on-rails 中,我创建一个种子文件并为每个测试加载客户。我可以将这个样板 Customer
放入测试类的属性中,这似乎是合乎逻辑的,但随后我将面临它被修改的风险。我有哪些选项可以简化此代码?
[TestMethod]
public class CustomerTests : TestClassBase
{
[TestMethod]
public void CanGetCustomerById()
{
// arrange
var customer = new Customer()
{
CustId = 5,
DifId = "55",
CustLookupName = "The Dude",
LoginList = new[] {
new Login { LoginCustId = 5, LoginName = "tdude" } }
};
var repository = Stub<ICustomerRepository>();
// act
repository.Stub(rep => rep.GetById(5)).Return(customer);
// assert
Assert.AreEqual(customer, repository.GetById(5));
}
[TestMethod]
public void CanGetCustomerByDifId()
{
// arrange
var customer = new Customer()
{
CustId = 5,
DifId = "55",
CustLookupName = "The Dude",
LoginList = new[] {
new Login { LoginCustId = 5, LoginName = "tdude" } }
};
var repository = Stub<ICustomerRepository>();
// act
repository.Stub(rep => rep.GetCustomerByDifID("55")).Return(customer);
// assert
Assert.AreEqual(customer, repository.GetCustomerByDifID("55"));
}
[TestMethod]
public void CanGetCustomerByLogin()
{
// arrange
var customer = new Customer()
{
CustId = 5,
DifId = "55",
CustLookupName = "The Dude",
LoginList = new[] {
new Login { LoginCustId = 5, LoginName = "tdude" } }
};
var repository = Stub<ICustomerRepository>();
// act
repository.Stub(rep =>
rep.GetCustomerByLogin("tdude")).Return(customer);
// assert
Assert.AreEqual(customer, repository.GetCustomerByLogin("tdude"));
}
}
测试基类
public class TestClassBase
{
protected T Stub<T>() where T : class
{
return MockRepository.GenerateStub<T>();
}
}
ICustomerRepository 和 IRepository
public interface ICustomerRepository : IRepository<Customer>
{
IList<Customer> FindCustomers(string q);
Customer GetCustomerByDifID(string difId);
Customer GetCustomerByLogin(string loginName);
}
public interface IRepository<T>
{
void Save(T entity);
void Save(List<T> entity);
bool Save(T entity, out string message);
void Delete(T entity);
T GetById(int id);
ICollection<T> FindAll();
}
I am embarking upon my first journey of test driven development in C#. To get started I'm using MSTest and Rhino.Mocks. I am attempting to write my first unit tests against my ICustomerRepository
. It seems tedious to new up a Customer
for each test method. In ruby-on-rails I'd create a seed file and load the customer for each test. It seems logical that I could put this boiler plate Customer
into a property of the test class but then I would run the risk of it being modified. What are my options for simplifying this code?
[TestMethod]
public class CustomerTests : TestClassBase
{
[TestMethod]
public void CanGetCustomerById()
{
// arrange
var customer = new Customer()
{
CustId = 5,
DifId = "55",
CustLookupName = "The Dude",
LoginList = new[] {
new Login { LoginCustId = 5, LoginName = "tdude" } }
};
var repository = Stub<ICustomerRepository>();
// act
repository.Stub(rep => rep.GetById(5)).Return(customer);
// assert
Assert.AreEqual(customer, repository.GetById(5));
}
[TestMethod]
public void CanGetCustomerByDifId()
{
// arrange
var customer = new Customer()
{
CustId = 5,
DifId = "55",
CustLookupName = "The Dude",
LoginList = new[] {
new Login { LoginCustId = 5, LoginName = "tdude" } }
};
var repository = Stub<ICustomerRepository>();
// act
repository.Stub(rep => rep.GetCustomerByDifID("55")).Return(customer);
// assert
Assert.AreEqual(customer, repository.GetCustomerByDifID("55"));
}
[TestMethod]
public void CanGetCustomerByLogin()
{
// arrange
var customer = new Customer()
{
CustId = 5,
DifId = "55",
CustLookupName = "The Dude",
LoginList = new[] {
new Login { LoginCustId = 5, LoginName = "tdude" } }
};
var repository = Stub<ICustomerRepository>();
// act
repository.Stub(rep =>
rep.GetCustomerByLogin("tdude")).Return(customer);
// assert
Assert.AreEqual(customer, repository.GetCustomerByLogin("tdude"));
}
}
Test Base Class
public class TestClassBase
{
protected T Stub<T>() where T : class
{
return MockRepository.GenerateStub<T>();
}
}
ICustomerRepository and IRepository
public interface ICustomerRepository : IRepository<Customer>
{
IList<Customer> FindCustomers(string q);
Customer GetCustomerByDifID(string difId);
Customer GetCustomerByLogin(string loginName);
}
public interface IRepository<T>
{
void Save(T entity);
void Save(List<T> entity);
bool Save(T entity, out string message);
void Delete(T entity);
T GetById(int id);
ICollection<T> FindAll();
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您的单元测试没有任何实际价值,因为它们只是测试 Rhino.Mocks。
您想要做的是使用 Rhino.Mocks 为需要 ICustomerRepository 的其他组件/服务创建 ICustomerRepository 存根。这样,您将使用存根的 ICustomerRepository,而不是使用与数据库或某些平面文件通信的 CustomerRepository,Rhino.Mocks 将允许您设置对某些方法的预定义响应,从而允许您在以下环境中测试您的服务:隔离。
Your unit tests don't have any real value because they're just testing Rhino.Mocks.
What you want to do is use Rhino.Mocks to create an ICustomerRepository stub for other components/services that need an ICustomerRepository. This way, instead of using a CustomerRepository that talks to a database or some flat file, you'll use the stubbed ICustomerRepository and Rhino.Mocks will let you set up pre-defined responses to certain methods, thus allowing you to test your services in isolation.
我会将创建客户的代码提取到一个方法中。您可以从测试方法中调用它,如果您将其命名为
SetUpCustomerForRepository
之类的名称,那么它将提供一些有关您正在执行的操作的文档。这是一个基于您的示例的示例:
您也可以从测试设置方法中调用它,但实际上我更喜欢在测试方法中执行此操作,以便查看测试的人知道正在为测试设置什么。
至于你担心它被修改......如果发生这种情况,那么你的测试将失败,你会知道的。
I would extract the code to create the customer into a method. You can call that from your test methods, and if you name it something like
SetUpCustomerForRepository
then it will provide some documentation about what you are doing.Here is an example based on your sample:
You could also call it from the test set up method, but I actually prefer to do it in the test method so that people looking at the test know what is being set up for the test.
As for your concern about it being modified....if that happens, then your tests will fail, and you'll know about it.
您可以通过修改存根和断言以使用其属性来使自己免受测试客户的更改:
You could immunize yourself against changes to your test customer by modifying your stubs and assertions to use its properties: