2

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

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

2 回答 2

2

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

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

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

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

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

于 2013-11-24T03:49:27.577 回答
2

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

唯一有意义的单元测试session.Save(itemType)是用你传入的任何东西调用的测试,然后session.Flush();被调用!这将验证这部分代码总是这样做......

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

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

要测试 nhibernate 自己的行为,您必须使用某种数据库进行集成测试,并且不模拟 nhibernate。

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

于 2013-11-24T07:40:38.737 回答