简体   繁体   English

单元测试-与外部依赖项隔离

[英]Unit Testing -Isolation from external dependencies

While writing unit test, we always say that we need to ensure that code is always isolated from external dependencies. 在编写单元测试时,我们总是说我们需要确保代码始终与外部依赖项隔离。 Below Moq has been used to provide a mocked object instead of a valid fluent nhibernate Session Factory. Moq下面已被用来提供模拟对象,而不是有效的流畅的休眠会话工厂。

  public class and_saving_a_invalid_item_type : 
  when_working_with_the_item_type_repository
  {
    private Exception _result;
    protected override void Establish_context()
    {
        base.Establish_context();
  _sessionFactory = new Mock<ISessionFactory>();
        _session = new Mock<ISession>();

       _sessionFactory.Setup(sf => sf.OpenSession()).Returns(_session.Object);         
        _itemTypeRepository = new ItemTypeRepository(_sessionFactory.Object);

       _session.Setup(s => s.Save(null)).Throws(new ArgumentNullException());
    }
    protected override void Because_of()
    {
        try
        {
            _itemTypeRepository.Save(null);
        }
        catch (Exception ex)
        {

            _result = ex;
        }

    }

    [Test]
    public void then_an_argument_null_exception_should_be_raised()
    {
        _result.ShouldBeInstanceOfType(typeof(ArgumentNullException));
    }
 }

The actual implementation is shown below. 实际的实现如下所示。 The test runs fine. 测试运行正常。 But without the expectation set to throw argumentnullexception , the save method actually return NullReferenceException. 但是,如果没有期望将其设置为引发argumentsnullexception,则save方法实际上返回NullReferenceException。 The point is: isn't the unit test obscuring the actual result. 关键是:单元测试是否会掩盖实际结果。 Though the requirement is fulfilled from unit testing point of view , it is not fulfilled actually while implemented. 尽管从单元测试的角度来看满足了要求,但在实施时却并未真正满足。

public class ItemTypeRepository : IItemTypeRepository
{
public int Save(ItemType itemType)
    {
        int id;
        using (var session = _sessionFactory.OpenSession())
        {
            id = (int) session.Save(itemType);                
            session.Flush();
        }
        return id;
    }
}

You are right since it is only NHibernate that gets tested in this example, and (edit: NHibernate's not tested either) that the test doesn't do much. 您是对的, 因为在此示例中仅测试了NHibernate,并且 (测试:NHibernate也未测试)该测试没有太大作用。 Even if the query is complex, most people choose to write an integration test against an in-memory database (or a real one) since it would test the same path and would be written anyway. 即使查询很复杂,大多数人还是选择针对内存数据库(或真实数据库)编写集成测试,因为它会测试相同的路径并且仍会编写。 Mocking the database usually returns little on the investment compared to integration tests. 与集成测试相比,模拟数据库通常不会带来多少投资。

These links can also help: 这些链接也可以帮助:

Update: This repository in the example surely has some purpose in life, for example it is going to be used by this class: 更新:示例中的此存储库肯定具有一定的用途,例如,该类将使用它:

class ItemUser {
   public ItemUser(IItemRepository repository) {}
}

My point is: testing ItemUser with a moq instance of IItemRepository is more fruitful. 我的观点是:用ItemUser的moq实例测试IItemRepository会更有成果。 Whether or not the item is really saved will be tested in the integration tests. 该项目是否真正保存将在集成测试中进行测试。

The test doesn't make a lot of sense because your are basically just testing that the mock returns an exception. 该测试没有多大意义,因为您基本上只是在测试该模拟返回异常。 You are not testing nhibernate, therefore the test has no real value. 您不是要测试nhibernate,因此测试没有实际价值。

The only unit test which would make sense is testing that session.Save(itemType) is called with whatever you pass in AND session.Flush(); 唯一有意义的单元测试是测试该session.Save(itemType)随您在AND session.Flush();传递的内容一起调用session.Flush(); gets called afterwards ! 之后被叫! This would validate that this part of code is always doing exactly that... 这将验证这部分代码始终在执行此操作...

There are some fundamental differences between unit testing business logic and integration testing data access. 单元测试业务逻辑和集成测试数据访问之间存在一些根本差异。

Your example is a typical data access class. 您的示例是典型的数据访问类。 You actually just wrap some nhibernate logic with your own Save method... 您实际上只是用自己的Save方法包装了一些休眠逻辑...

To test nhibernate's very own behavior, you have to do integration testing with some kind of database and without mocking out nhibernate. 要测试nhibernate自己的行为,您必须对某种数据库进行集成测试,而不能模拟nhibernate。

Anyways, one small thing regarding the code you posted. 无论如何,关于您发布的代码的一件小事。 You should actually check against null yourself at that point because the method is public and you expect some value not being null. 此时,您实际上应该自己检查null,因为该方法是公共的,并且您希望某些值不为null。 Don't let nhibernate fail later. 不要让nhibernate稍后失败。 Simply do a null check. 只需做一个空检查。 And unit test that. 然后进行单元测试。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM