对接口存储库进行单元测试的目的是什么

发布于 2024-09-06 02:31:19 字数 1919 浏览 4 评论 0原文

我正在对用于检索 Customer 类型的对象的 ICustomerRepository 接口进行单元测试。

  • 作为单元测试,通过以这种方式测试 ICustomerRepository 我可以获得什么价值?
  • 在什么条件下以下测试会失败?
  • 对于这种性质的测试,是否建议进行我知道应该失败的测试?即,当我知道我只在存储库中放置了 5 时,寻找 id 4

我可能错过了一些明显的东西,但似乎实现了 的类的集成测试>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 placed 5 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

筱武穆 2024-09-13 02:31:19

我可能遗漏了一些东西,但似乎你测试的每个方面都被模拟了?

一般来说,您只模拟非测试核心的对象。在这种情况下,您可以使用此存储库作为您希望使用存储库执行某些操作以检索客户 #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.

那片花海 2024-09-13 02:31:19

测试规则#1:

在编写测试之前,了解测试的目的是什么以及它试图证明什么。如果您不知道它证明了什么,那么它就没用了:)

正如其他发帖者正确所说的那样,您正在存根一个接口,然后调用该存根 - 这并不能证明您的生产代码是否有效。

什么是存根?

存根用于提供固定值来驱动被测类的某些方面。例如,假设您有一个 CustomerService,它有一个 ICustomerRepository 类型的实例。如果您希望看到 CustomerService 在存储库为空时能够正常处理错误情况,您可以对 ICustomerRepositoryGetCustomerById 方法进行存根处理不返回任何内容/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 type ICustomerRepository. If you wanted to see that the CustomerService could gracefully handle an error case when the repository was empty, you would stub the ICustomerRepository's GetCustomerById method to return nothing/null/throw an exception, then ensure that the CustomerService 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 stubbed ICustomerRepository 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.

吃不饱 2024-09-13 02:31:19

根据定义,接口只是契约,因此无需测试代码。您希望针对接口的具体实现编写单元测试,因为那是实际执行代码所在的位置。

如果接口没有具体的实现,而您只是模拟具体的实现,那么您的单元测试只是基于模拟。这其实没有多大价值。

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.

时光瘦了 2024-09-13 02:31:19

你的测试对我来说毫无意义。您正在测试预编程的存根是否返回您提供的值,您没有测试任何实际代码。

关注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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文