Getting started with TDD and the repository pattern, I'm wondering if it makes any sense testing this...
开始使用TDD和存储库模式,我想知道测试这个是否有意义......
Using the repository pattern, I have this interface:
使用存储库模式,我有这个接口:
public interface ICustomerRepository
{
IList<Customer> List();
Customer Get(int id);
}
I have like 50 different entities, so 50 different repository interfaces/implementations.
我有50个不同的实体,所以50个不同的存储库接口/实现。
My question is if it's correct to test each repository, by mocking up the interface, like:
我的问题是,通过模拟界面测试每个存储库是否正确,如:
[TestMethod]
public void List_Should_Return_Two_Customers()
{
// Arrange
var customerr = new List<Customer>();
customer.Add(new Customer());
customer.Add(new Customer());
var repository = new Mock<ICustomerRepository>();
repository.Setup(r => r.List()).Returns(customer);
// Assert
Assert.AreEqual(2, repository.Object.List().Count);
}
[TestMethod]
public void Get_Should_Return_One_Customer()
{
// Arrange
var customer = new List<Customer>();
customerr.Add(new Customer() { Id = 1 });
customerr.Add(new Customer() { Id = 2 });
var repository = new Mock<ICustomerRepository>();
repository.Setup(r => r.Get(1)).Returns(customer.Where(w => w.Id == 1).First());
// Assert
Assert.IsTrue(repository.Object.Get(1).Id == 1);
}
Does it make any sense testing a fake implementation of these interfaces? To me it does not.
测试这些接口的虚假实现是否有意义?对我而言,事实并非如此。
4 个解决方案
#1
No, it does not make sense. Obviously you should test only implementations, not interfaces. There is nothing to test in an interface.
不,这没有意义。显然你应该只测试实现,而不是接口。在界面中没有可测试的东西。
The only things being tested in your examples are the mocking framework, the .NET list and some LINQ extension methods. There is no need to test those, somebody else already takes care of that.
在您的示例中测试的唯一内容是模拟框架,.NET列表和一些LINQ扩展方法。没有必要对这些进行测试,其他人已经在考虑这一点。
Maybe the intention was to provide unit tests for the fact that the interface exists and has certain methods? In that case, the tests are still unnecessary. This is implicitly tested by the tests for other code that relies on the interface declaration.
也许意图是为界面存在并具有某些方法的事实提供单元测试?在这种情况下,测试仍然是不必要的。这是由依赖于接口声明的其他代码的测试隐式测试的。
You should only create an ICustomerRepository
mock when you need a fake implementation in order to test other code.
只有在需要虚假实现才能测试其他代码时,才应创建ICustomerRepository模拟。
#2
Yes, it is "correct" to test each Repository. Repositories exist to abstract your database away from the code, and should be verified that they are working correctly. Your data access layer is arguably one of the most important components to test.
是的,测试每个存储库是“正确的”。存储库用于将数据库从代码中抽象出来,并且应该验证它们是否正常工作。您的数据访问层可以说是最重要的测试组件之一。
#3
The others are right. You can't test interfaces. You are in fact testing mocks, and that doesn't make sense. Usually I test repositories against a database, so, not so much unit testing for them. And for testing anything above them I mock them. Keep in mind that 50 types of entities doesn't mean 50 repositories.
其他人都是对的。你无法测试接口。你实际上正在测试模拟,这没有意义。通常我会针对数据库测试存储库,因此,对它们进行单元测试并不是那么多。为了测试他们之上的任何东西我嘲笑他们。请记住,50种类型的实体并不意味着50个存储库。
Regards.
#4
Can I propose an alternate solution... As Simple as your Repository is (if they are all the same methods except for what they return) why don't you make a base class using Generics. Then you would only have to test the base class.
我可以提出一个替代解决方案......就像您的存储库一样简单(如果它们都是相同的方法,除了它们返回的内容)为什么不使用泛型创建基类。那么你只需要测试基类。
public interface IRepository<TEntity> where TEntity : class
{
IList<TEntity> List();
TEntity Get(int id);
}
public abstract class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : class
{
IList<TEntity> List()
{
//DataContext.GetTable<TEntity>().ToList();
}
TEntity Get(int id)
{
//Might have to do some magic here... you can use reflection or create
//an abstract method that the derived class must override that returns
//a delegate id selector.
}
}
#1
No, it does not make sense. Obviously you should test only implementations, not interfaces. There is nothing to test in an interface.
不,这没有意义。显然你应该只测试实现,而不是接口。在界面中没有可测试的东西。
The only things being tested in your examples are the mocking framework, the .NET list and some LINQ extension methods. There is no need to test those, somebody else already takes care of that.
在您的示例中测试的唯一内容是模拟框架,.NET列表和一些LINQ扩展方法。没有必要对这些进行测试,其他人已经在考虑这一点。
Maybe the intention was to provide unit tests for the fact that the interface exists and has certain methods? In that case, the tests are still unnecessary. This is implicitly tested by the tests for other code that relies on the interface declaration.
也许意图是为界面存在并具有某些方法的事实提供单元测试?在这种情况下,测试仍然是不必要的。这是由依赖于接口声明的其他代码的测试隐式测试的。
You should only create an ICustomerRepository
mock when you need a fake implementation in order to test other code.
只有在需要虚假实现才能测试其他代码时,才应创建ICustomerRepository模拟。
#2
Yes, it is "correct" to test each Repository. Repositories exist to abstract your database away from the code, and should be verified that they are working correctly. Your data access layer is arguably one of the most important components to test.
是的,测试每个存储库是“正确的”。存储库用于将数据库从代码中抽象出来,并且应该验证它们是否正常工作。您的数据访问层可以说是最重要的测试组件之一。
#3
The others are right. You can't test interfaces. You are in fact testing mocks, and that doesn't make sense. Usually I test repositories against a database, so, not so much unit testing for them. And for testing anything above them I mock them. Keep in mind that 50 types of entities doesn't mean 50 repositories.
其他人都是对的。你无法测试接口。你实际上正在测试模拟,这没有意义。通常我会针对数据库测试存储库,因此,对它们进行单元测试并不是那么多。为了测试他们之上的任何东西我嘲笑他们。请记住,50种类型的实体并不意味着50个存储库。
Regards.
#4
Can I propose an alternate solution... As Simple as your Repository is (if they are all the same methods except for what they return) why don't you make a base class using Generics. Then you would only have to test the base class.
我可以提出一个替代解决方案......就像您的存储库一样简单(如果它们都是相同的方法,除了它们返回的内容)为什么不使用泛型创建基类。那么你只需要测试基类。
public interface IRepository<TEntity> where TEntity : class
{
IList<TEntity> List();
TEntity Get(int id);
}
public abstract class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : class
{
IList<TEntity> List()
{
//DataContext.GetTable<TEntity>().ToList();
}
TEntity Get(int id)
{
//Might have to do some magic here... you can use reflection or create
//an abstract method that the derived class must override that returns
//a delegate id selector.
}
}