2013-11-24 65 views
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)); 
    } 
} 

实际执行情况如下所示。测试运行良好。但是如果没有设置抛出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

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

这些链接还可以帮助:

更新:该库中的例子肯定在生活中的一些目的,例如它会本类使用:

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

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

+0

然后,如果最终我们需要编写集成测试,那么通过使用模拟框架进行隔离的单元测试的目的是什么? – arjun

+0

你可以在不嘲笑ISessionFactory的情况下嘲笑版本库;例如:只是测试逻辑,假装项目被保存在存储库中;这就是集成测试中要测试的内容。请参阅更新。 – henginy

2

这个测试没有什么意义,因为你基本上只是在测试模拟返回一个异常。你没有测试nhibernate,因此测试没有实际价值。

唯一的单元测试这将使意义正在测试session.Save(itemType)被称为不管你传递和session.Flush();被称为事后! 这将验证这部分代码始终在做着这些...

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

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

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

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