2013-10-12 96 views
0

我对80%简单逻辑和20%复杂逻辑的项目进行TDD。如果证明方法抛出错误并且怀疑正确的方法,我发现自己测试了很多。我使用NUnit和JustMock。测试异常的正确方法

我有两种方法来做到这一点。使用ExpectedException属性并分类类型。或者写下如下。写如下的专业版,我也可以断言exception.message(如果我做了一个自定义的),并且如果测试失败,我也会显示exception.message。但我想与他人核对你是如何做到的。所以总结一下:

  1. 对这样的例外进行大量测试是否正常?
  2. 这是做正确的方式:

只是解释:一个供应商提供某些合同,一处接受一个合同,但不能有同一个供应商一个以上的合同(但五言可以有不同的供应商不同的合同)

[Test] 
    public void Accepting_more_than_one_contract_from_supplier_throws_exception() 
    { 
     //Arrange 
     var department = new Department(Guid.NewGuid(), "1234"); 
     var supplier = Mock.Create<Supplier>(); 
     var contract1 = Mock.Create<DeliveryContract>(); 
     var contract2 = Mock.Create<DeliveryContract>(); 
     var id = Guid.NewGuid(); 
     supplier.Arrange(x => x.Id).Returns(id); 
     contract1.Arrange(x => x.Supplier).Returns(supplier); 
     contract2.Arrange(x => x.Supplier).Returns(supplier); 

     //Act 
     department.AcceptContract(contract1); 

     //Assert 
     try 
     { 
      department.AcceptContract(contract2); 
      Assert.Fail("Duplicate contract with supplier did not throw an exception"); 
     } 
     catch (Exception ex) 
     { 
      Assert.AreEqual(typeof(ArgumentException),ex.GetType(),ex.Message); 
     } 
    } 

回答

6

您可以使用Assert.Throws方法:

Assert.Throws<ArgumentException>(() => department.AcceptContract(contract2)); 

Assert.Throws<ArgumentException>(() => department.AcceptContract(contract2), "some message"); 
+0

这是一个更好的办法来做到这一点比上面? – cfs

+0

是的,它在NUnit中定义。你不觉得它比try-catch块更好吗? –

+0

是的,我确实这么认为,但ExceptionAttribute也是这样;)但我认为try/catch块确实显示了测试的内涵,以及它应该如何工作。此外,还可以断言异常消息,这更加独特。在声明错误的争论性错误时有一些问题,例如,如果我在另一个字段中检查空字符串,并抛出一个ArgumentException,并且测试通过了错误的条件。 – cfs

2

正如@Ufuk说。使用Assert.Throws<T>其中T是一种例外类型。

如果你还需要检查异常消息使用这一个:

T Assert.Throws<T>(TestDelegate code, string message); 
T Assert.Throws<T>(TestDelegate code, string message, 
     params object[] parms); 

顺便说一句,你的测试创建不应该嘲笑,但存根数据。 通过存根我的意思是只包含测试数据的对象,在你的情况下,你提供对象的行为 - 而不是数据。

我建议你使用NBuilder code.google.com/p/nbuilder/。您可以通过它创建清楚的存根。它也具有很大的创建对象的灵活性,可以随机或准确地为您的测试用例创建它们。

的使用你的情况:

var supplierStub = Builder<Supplier> 
       .With(supplier => supplier.Id = id) 
       .Build(); 

var contractsStub = Builder<DeliveryContract>.CreateListOfSize(2) 
       .All() 
        .With(contract => contract.Supplier = supplierStub) 
       .Build(); 

+0

感谢您对NBuilder的建议。只有一个问题,你发现自己做了很多这样的测试,还是测试这样的例外的代码是错误的? – cfs

+1

它依赖于类逻辑流程。在你的例子中抛出异常并不明显,它是类逻辑的一部分,所以测试它是合理的。请记住,测试可能是您的代码的良好文档。 我正在测试大多数情况下,当我把它们直接抛出代码(通过throw)或程序在某些情况下抛出异常的异常代码。 对我来说,很好的例子是测试servis负责阅读.xml文件f.e.由LinqToXml。要测试的好例子是如果一个节点缺失,服务将如何运作。 – michalczukm