对接口存储库进行单元测试的目的是什么
我正在对用于检索 Customer
类型的对象的 ICustomerRepository
接口进行单元测试。
- 作为单元测试,通过以这种方式测试
ICustomerRepository
我可以获得什么价值? - 在什么条件下以下测试会失败?
- 对于这种性质的测试,是否建议进行我知道应该失败的测试?即,当我知道我只在存储库中放置了
5
时,寻找 id4
我可能错过了一些明显的东西,但似乎实现了 的类的集成测试>ICustomerRepository
将具有更多价值。
[TestClass]
public class CustomerTests : TestClassBase
{
private Customer SetUpCustomerForRepository()
{
return new Customer()
{
CustId = 5,
DifId = "55",
CustLookupName = "The Dude",
LoginList = new[]
{
new Login { LoginCustId = 5, LoginName = "tdude" },
new Login { LoginCustId = 5, LoginName = "tdude2" }
}
};
}
[TestMethod]
public void CanGetCustomerById()
{
// arrange
var customer = SetUpCustomerForRepository();
var repository = Stub<ICustomerRepository>();
// act
repository.Stub(rep => rep.GetById(5)).Return(customer);
// assert
Assert.AreEqual(customer, repository.GetById(5));
}
}
测试基类
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 unit testing an ICustomerRepository
interface used for retrieving objects of type Customer
.
- As a unit test what value am I gaining by testing the
ICustomerRepository
in this manner? - Under what conditions would the below test fail?
- For tests of this nature is it advisable to do tests that I know should fail? i.e. look for id
4
when I know I've only placed5
in the repository
I am probably missing something obvious but it seems the integration tests of the class that implements ICustomerRepository
will be of more value.
[TestClass]
public class CustomerTests : TestClassBase
{
private Customer SetUpCustomerForRepository()
{
return new Customer()
{
CustId = 5,
DifId = "55",
CustLookupName = "The Dude",
LoginList = new[]
{
new Login { LoginCustId = 5, LoginName = "tdude" },
new Login { LoginCustId = 5, LoginName = "tdude2" }
}
};
}
[TestMethod]
public void CanGetCustomerById()
{
// arrange
var customer = SetUpCustomerForRepository();
var repository = Stub<ICustomerRepository>();
// act
repository.Stub(rep => rep.GetById(5)).Return(customer);
// assert
Assert.AreEqual(customer, repository.GetById(5));
}
}
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我可能遗漏了一些东西,但似乎你测试的每个方面都被模拟了?
一般来说,您只模拟非测试核心的对象。在这种情况下,您可以使用此存储库作为您希望使用存储库执行某些操作以检索客户 #5 并对其执行操作的函数的源。
例如,您可以模拟客户存储库,以便可以调用验证用户登录的方法。您可以使用模拟存储库来防止单元测试依赖真实的数据源,而不是测试您的模拟存储库。
I may be missing something but it seems like every single aspect of your test is mocked up?
Generally speaking you only mock up the objects that aren't core to the test. In this case you may use this repository as the source for a function which you expect to do something with the repository to retrieve customer #5 and perform an operation on it.
For example you may mock up a customer repository so that you can call a method that verifies the login of a user. You'd use your mock repository to prevent your unit-test from relying on a real data-source, not to test your mock repository.
测试规则#1:
在编写测试之前,了解测试的目的是什么以及它试图证明什么。如果您不知道它证明了什么,那么它就没用了:)
正如其他发帖者正确所说的那样,您正在存根一个接口,然后调用该存根 - 这并不能证明您的生产代码是否有效。
什么是存根?
存根用于提供固定值来驱动被测类的某些方面。例如,假设您有一个
CustomerService
,它有一个ICustomerRepository
类型的实例。如果您希望看到CustomerService
在存储库为空时能够正常处理错误情况,您可以对ICustomerRepository
的GetCustomerById
方法进行存根处理不返回任何内容/null/抛出异常,然后确保CustomerService
方法执行正确的操作(例如返回未找到客户的结果)。即存根只是一个协作者,可以帮助您达到感兴趣的特定条件/行为。我们正在测试
CustomerService
,而存根的ICustomerRepository
只是帮助我们实现目标。你不是第一个问这个问题的人:)。我通常建议开发人员首先手动滚动他们的测试替身。它有助于理解所有交互以及框架实际上为您做什么。
Rule #1 of testing:
Know what the purpose of your test is and what it is trying to prove before you write it. If you don't know what it proves, then it's useless :)
As the other posters have correctly said, you're stubbing an interface and then calling the stub -- this doesn't prove anything about whether your production code works.
What is a stub?
Stubs are used to provide canned values to drive some aspect of the class under test. E.g. Say you have a
CustomerService
that has an instance of typeICustomerRepository
. If you wanted to see that theCustomerService
could gracefully handle an error case when the repository was empty, you would stub theICustomerRepository
'sGetCustomerById
method to return nothing/null/throw an exception, then ensure that theCustomerService
method did the correct thing (e.g. return a customer not found result).I.e. the stub is just a collaborator that helps you reach the particular condition/behaviour of interest. We're testing
CustomerService
and the stubbedICustomerRepository
merely helps us achieve our goal.You're not the first to ask this very question :). I usually advise developers to hand-roll their test doubles at first. It helps to understand all of the interactions and what the framework is actually doing for you.
根据定义,接口只是契约,因此无需测试代码。您希望针对接口的具体实现编写单元测试,因为那是实际执行代码所在的位置。
如果接口没有具体的实现,而您只是模拟具体的实现,那么您的单元测试只是基于模拟。这其实没有多大价值。
Interfaces, by definition, are just contracts, so there's no code to test. You want to write unit tests against the concrete implementation(s) of the interface, because that is where the actual execution code lives.
If there's no concrete implementation of the interface and you're just mocking a concrete implementation, then your unit test is just based on a mock. That isn't really of much value.
你的测试对我来说毫无意义。您正在测试预编程的存根是否返回您提供的值,您没有测试任何实际代码。
关注dcp的回复。接口是方法的声明。您应该测试这些的实现。
Your test makes no sense to me. You are testing if a preprogrammed stub is returning the values you feed it, You are not testing any real code.
Follow dcp's reply. An interface is a declaration of methods. You should test implementations of these.