ASP.NET MVC - 如何在存储库模式中对边界进行单元测试?

发布于 2024-09-01 12:28:23 字数 1016 浏览 5 评论 0原文

给定一个基本的存储库接口:

public interface IPersonRepository
{
    void AddPerson(Person person);
    List<Person> GetAllPeople();
}

通过一个基本的实现:

public class PersonRepository: IPersonRepository
{
    public void AddPerson(Person person) 
    {
        ObjectContext.AddObject(person);
    }

    public List<Person> GetAllPeople()
    {
        return ObjectSet.AsQueryable().ToList();
    }
}

如何以有意义的方式对其进行单元测试?由于它跨越边界并物理更新并从数据库读取,因此这不是单元测试,而是集成测试。

或者一开始就想对其进行单元测试是错误的吗?我应该只对存储库进行集成测试吗?

我一直在谷歌上搜索这个主题,博客经常说制作一个实现 IRepository 的存根:

public class PersonRepositoryTestStub: IPersonRepository
{
    private List<Person> people = new List<Person>();
    public void AddPerson(Person person) 
    {
        people.Add(person);
    }

    public List<Person> GetAllPeople()
    {
        return people;
    }
}

但这并不对 PersonRepository 进行单元测试,它测试 PersonRepositoryTestStub 的实现(不是很有帮助)。

Given a basic repository interface:

public interface IPersonRepository
{
    void AddPerson(Person person);
    List<Person> GetAllPeople();
}

With a basic implementation:

public class PersonRepository: IPersonRepository
{
    public void AddPerson(Person person) 
    {
        ObjectContext.AddObject(person);
    }

    public List<Person> GetAllPeople()
    {
        return ObjectSet.AsQueryable().ToList();
    }
}

How can you unit test this in a meaningful way? Since it crosses the boundary and physically updates and reads from the database, thats not a unit test, its an integration test.

Or is it wrong to want to unit test this in the first place? Should I only have integration tests on the repository?

I've been googling the subject and blogs often say to make a stub that implements the IRepository:

public class PersonRepositoryTestStub: IPersonRepository
{
    private List<Person> people = new List<Person>();
    public void AddPerson(Person person) 
    {
        people.Add(person);
    }

    public List<Person> GetAllPeople()
    {
        return people;
    }
}

But that doesnt unit test PersonRepository, it tests the implementation of PersonRepositoryTestStub (not very helpful).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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

评论(4

一个人的旅程 2024-09-08 12:28:23

在这种特定情况下,我认为您不需要为存储库类进行单元测试,因为实现只是调用 ObjectContext 对象,所以这就像测试您没有构建的东西(这不是这个想法)。如果您没有任何复杂的逻辑,我的建议是不要浪费时间为该类进行单元测试。您所说的 PersonRepositoryTestStub 是存储库的一个假实现,用于测试 DAL 之上的层。

In this specific case I think you don't need to make a unit test for your repository class, as the implementation is simply invoking the ObjectContext object, so it will be like testing something you didn't build (which is not the idea). In case you don't have any complex logic, my recommendation is not to waste time on making a unit test for that class. What you say about the PersonRepositoryTestStub is a fake implementation of the repository for testing the layer that is above of your DAL.

追星践月 2024-09-08 12:28:23

我遇到了同样的问题。我针对我的存储库接口的实现编写了大量单元测试,该存储库接口是一个假存储库。完成后不久,我意识到我编写单元测试是为了测试假存储库,而我编写假存储库只是为了支持单元测试。这看起来像是大量无用的代码。

我得出的结论是,我不需要单元测试,但假存储库实现很好,因为我可以将它用作我的服务(以及我的控制器)使用的存储库,以便针对这些的单元测试是可预测的(感谢预定义的假存储库)。

因此,我决定将针对假存储库的单元测试保留在那里,因为它们有助于测试我的假存储库,以便我可以放心,我的应用程序的更高级别正在使用经过充分测试的假存储库。

换句话说,假存储库和针对假存储库的单元测试是更高级别应用程序的“支持演员”以及针对更高级别应用程序的单元测试。

希望有帮助。

I have run into the same problem. I wrote a slew of unit tests against an implementation of my repository interface that was a fake repository. Shortly after completing it, I realized that I wrote the unit test to test the fake repository and I wrote the fake repository simply to support the unit tests. This seemed like a large amount of useless code.

I have come to the conclusion that I don't need the unit tests but that the fake repository implementation is good because I can use it as the repository my services (and therefore my controllers) use so that unit tests against those will be predictable (thanks to a predefined fake repository).

So, I have decided to leave the unit tests against the fake repository in there as they are helpful to test my fake repository so that I can be assured that the higher levels of my application are using fully tested fakes.

In other words, the fake repository and the unit tests against the fake repository are the "supporting cast" for higher levels of the applications and the unit tests against higher levels of the application.

Hope that helps.

情释 2024-09-08 12:28:23

我认为这种类型的测试有意义的时候是当你的存储库接口是通用的时。例如,

public interface IEntity
{
    int Id { get; set; }
}

public interface IRepository<TEntity>
    where TEntity : IEntity
{
    void Add(TEntity entity);
    List<TEntity> GetAll();
}

如果您有该接口的多个实现,那么还可以编写一个针对该接口进行测试的通用测试装置,从而允许您使用单个测试装置测试多个存储库实现。这种方法不区分单元测试和集成测试,因为它不知道实现是什么。

如果您对此类事情感兴趣,请告诉我,我可以发布一个完整的示例。

The time when I think this type of testing makes sense is when your repository interface is generic. E.g.

public interface IEntity
{
    int Id { get; set; }
}

public interface IRepository<TEntity>
    where TEntity : IEntity
{
    void Add(TEntity entity);
    List<TEntity> GetAll();
}

If you have multiple implementations of that interface, then it is also possible to write a generic test fixture that tests against that interface, allowing you to test multiple repository implementations with a single test fixture. This approach does not differentiate between unit and integration tests, because it has no idea what the implementation is.

Let me know if this type of thing interests you and I can post a complete example.

看春风乍起 2024-09-08 12:28:23

我将测试直接依赖于 DAL 实现(对 DAL 精确实现具有强引用)或间接依赖于 DAL 实现(通过接口从 DAL 抽象)的业务逻辑层。

我不太喜欢使用存根实现的测试,只需将数据库调用包装到未提交的事务中(当测试完成时,即使抛出异常,也会回滚所有数据更改)。

I would test Business Logic layer that depends on DAL implementation directly (has strong reference to DAL exact implementation) or indirectly (abstracted from DAL via interfaces).

I am not very fond of tests, that uses stub implementation, just wrap database calls into uncomitted transaction (that rolls back all data changes when test finishes even if exception is thrown).

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