单元测试 - 来自外部依赖项的隔离

时间:2013-11-24 03:00:45

标签: c# unit-testing nhibernate nbehave

在编写单元测试时,我们总是说我们需要确保代码始终与外部依赖关系隔离。 Moq下面用于提供模拟对象,而不是有效的流畅的nhibernate Session Factory。

  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));
    }
 }

实际实施如下所示。测试运行正常。但是如果没有期望设置throw argumentnullexception,save方法实际上返回NullReferenceException。关键是:不是单元测试模糊了实际结果。虽然从单元测试的角度来看这个要求是满足的,但实际上并没有实现。

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;
    }
}

2 个答案:

答案 0 :(得分:2)

你是正确的,因为只有NHibernate在这个例子中得到测试,并且(编辑:NHibernate也未测试)测试没有做太多。即使查询很复杂,大多数人也会选择针对内存数据库(或真实数据库)编写集成测试,因为它会测试相同的路径并且无论如何都会被编写。与集成测试相比,模拟数据库通常在投资上几乎没有回报。

这些链接也可以提供帮助:

更新:示例中的这个存储库肯定有一些生命中的目的,例如它将被这个类使用:

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

我的观点是:使用ItemUser的moq实例测试IItemRepository会更有成效。是否真正保存该项目将在集成测试中进行测试。

答案 1 :(得分:2)

测试没有多大意义,因为您基本上只是测试模拟返回异常。你没有测试nhibernate,因此测试没有实际价值。

唯一有意义的单元测试是测试session.Save(itemType)被调用时传入的任何内容和session.Flush();之后被称为 ! 这将验证代码的这一部分总是完全正确...

单元测试业务逻辑和集成测试数据访问之间存在一些根本区别。

您的示例是典型的数据访问类。实际上你只需用你自己的Save方法包装一些nhibernate逻辑......

要测试nhibernate自己的行为,你必须使用某种数据库进行集成测试,而不必嘲笑nhibernate。

无论如何,关于你发布的代码有一点小事。实际上,您应该在那时自己检查null,因为该方法是公共的,并且您希望某些值不为null。不要让nhibernate以后失败。只需进行空检查。单元测试。