2008-09-22 20 views
38

Visual Studio Test có thể kiểm tra các ngoại lệ dự kiến ​​bằng cách sử dụng thuộc tính ExpectedException. Bạn có thể vượt qua trong một ngoại lệ như thế này:Làm cách nào để kiểm tra ngoại lệ được mong đợi bằng thông báo ngoại lệ cụ thể từ tệp tài nguyên trong Visual Studio Test?

[TestMethod] 
[ExpectedException(typeof(CriticalException))] 
public void GetOrganisation_MultipleOrganisations_ThrowsException() 

Bạn cũng có thể kiểm tra các thông điệp chứa trong ExpectedException như thế này:

[TestMethod] 
[ExpectedException(typeof(CriticalException), "An error occured")] 
public void GetOrganisation_MultipleOrganisations_ThrowsException() 

Nhưng khi kiểm tra các ứng dụng I18N Tôi sẽ sử dụng một tập tin tài nguyên để có được thông báo lỗi đó (bất kỳ thông báo lỗi nào thậm chí có thể quyết định kiểm tra các bản địa hóa khác nhau của thông báo lỗi nếu tôi muốn, nhưng Visual Studio sẽ không cho phép tôi làm điều này:

[TestMethod] 
[ExpectedException(typeof(CriticalException), MyRes.MultipleOrganisationsNotAllowed)] 
public void GetOrganisation_MultipleOrganisations_ThrowsException() 

Compil er sẽ đưa ra lỗi sau:

An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute

Có ai biết cách kiểm tra ngoại lệ có thông báo từ tệp tài nguyên không?


Một lựa chọn Tôi đã xem xét là sử dụng lớp tùy chỉnh ngoại lệ, nhưng dựa trên lời khuyên thường nghe như:

"Do create and throw custom exceptions if you have an error condition that can be programmatically handled in a different way than any other existing exception. Otherwise, throw one of the existing exceptions." Source

Tôi không mong đợi để xử lý các trường hợp ngoại lệ khác nhau trong dòng chảy bình thường (đó là một ngoại lệ quan trọng, vì vậy tôi đang đi vào chế độ hoảng loạn anyway) và tôi không nghĩ rằng việc tạo ra một ngoại lệ cho mỗi trường hợp thử nghiệm là điều đúng để làm. Bạn có ý kiến ​​gì không?

+3

Tham số thông điệp không được kiểm tra đối với thông điệp của ngoại lệ được ném. –

Trả lời

7

Chỉ một ý kiến, nhưng tôi có thể nói văn bản lỗi:

  • là một phần của bài kiểm tra, trong trường hợp nhận được nó từ nguồn sẽ là 'sai' (nếu không bạn có thể kết thúc với một cách nhất quán tài nguyên bị cắt xén), vì vậy, chỉ cần cập nhật thử nghiệm khi bạn thay đổi tài nguyên (hoặc thử nghiệm không thành công)
  • không phải là một phần của thử nghiệm và bạn chỉ nên quan tâm đến nó.

Lưu ý rằng tùy chọn đầu tiên sẽ cho phép bạn kiểm tra nhiều ngôn ngữ, với khả năng chạy với ngôn ngữ.

Đối với nhiều trường hợp ngoại lệ, tôi đến từ đất C++, nơi tạo tải và tải ngoại lệ (đến điểm một lần cho mỗi câu lệnh 'ném'!) Trong những người thừa kế lớn là chấp nhận được (nếu không phổ biến). siêu dữ liệu hệ thống có lẽ không thích điều đó, do đó lời khuyên đó.

+0

Tôi sẽ thực hiện một proc đơn giản đọc tệp tài nguyên và tìm thấy thông báo được viết, phương pháp của bạn là một cách tuyệt vời để loại bỏ bản đồ và mất thời gian kiểm tra cập nhật có giá trị (những gì chúng tôi cố gắng tránh) –

+0

@Mickey: Well sau đó, bạn đang ở may mắn: câu trả lời khác là những gì bạn đang tìm kiếm! Nếu bạn * cụ thể * muốn một đơn vị ** ** - kiểm tra xem nó có nhận được cùng một thông điệp hay không, thì tốt, nhưng tôi có xu hướng muốn nó nhận được thông báo * đúng *. Nhưng nếu dự án của bạn khác, thì bạn có thể dễ dàng có câu trả lời "đúng" khác! –

+0

Tôi không làm theo, bằng cách sử dụng thử nghiệm Đơn vị dữ liệu, bạn có thể giữ cho bánh của bạn và ăn nó quá. ánh xạ các tài nguyên trong databind và ánh xạ văn hóa thông điệp của bạn trong bài kiểm tra, hoặc ngược lại. không? –

4

Tôi nghĩ rằng bạn chỉ có thể thực hiện thử thách rõ ràng trong mã thử nghiệm thay vì dựa vào thuộc tính ExpectedException để làm điều đó cho bạn. Sau đó, bạn có thể đến với một số phương pháp trợ giúp sẽ đọc các tập tin tài nguyên và so sánh các thông báo lỗi với một trong đó đi kèm với ngoại lệ đã bị bắt. (Tất nhiên nếu không có một ngoại lệ thì trường hợp thử nghiệm nên được coi là một thất bại)

3

Nếu bạn chuyển sang sử dụng thư viện xUnit.Net thử nghiệm rất tốt đẹp, bạn có thể thay thế [ExpectedException] với một cái gì đó như thế này:

[Fact] 
public void TestException() 
{ 
    Exception ex = Record.Exception(() => myClass.DoSomethingExceptional()); 
    // Assert whatever you like about the exception here. 
} 
1

Tôi tự hỏi nếu NUnit đang di chuyển xuống con đường đi từ sự đơn giản ... nhưng ở đây bạn đi.

Tính năng nâng cao mới (2.4.3 trở lên) cho thuộc tính ExpectedException cho phép bạn kiểm soát nhiều hơn đối với các kiểm tra được thực hiện trên Ngoại lệ dự kiến ​​thông qua phương thức xử lý. Chi tiết khác trên official NUnit doc page .. về phía cuối trang.

[ExpectedException(Handler="HandlerMethod")] 
public void TestMethod() 
{ 
... 
} 

public void HandlerMethod(System.Exception ex) 
{ 
... 
} 

Lưu ý: Một cái gì đó không cảm thấy ngay tại đây .. Tại sao thông điệp ngoại lệ của bạn quốc tế hóa .. Bạn đang sử dụng ngoại lệ cho những thứ mà cần phải được xử lý hoặc thông báo cho người dùng. Trừ khi bạn có một loạt các nhà phát triển đa dạng về văn hóa sửa lỗi .. bạn không nên cần điều này. Ngoại lệ bằng tiếng Anh hoặc một ngôn ngữ được chấp nhận phổ biến sẽ đủ. Nhưng trong trường hợp bạn phải có điều này .. nó có thể :)

+0

Bạn không nghĩ rằng phương pháp nhận được thông báo hộp thoại lỗi từ ngoại lệ ném là thiết kế tốt? Tôi đã bị ấn tượng vì nó là phổ biến, và nó đơn giản hóa mã lỗi đường dẫn ... Tôi biết tôi sẽ không muốn nhìn thấy một hộp thoại bằng tiếng Trung! –

+0

Tôi đang sử dụng khung NUnit phiên bản 2.6 và thuộc tính [ExpectedException (Handler = "HandlerMethod")] không biên dịch – dotnetguy

+0

@mishrsud - Tôi tin rằng trình biên dịch sẽ cung cấp cho bạn thêm chi tiết về điều đó. Kiểm tra ngăn đầu ra - nó phàn nàn về điều gì? – Gishu

63

Tôi khuyên bạn nên sử dụng phương pháp trợ giúp thay vì thuộc tính. Một cái gì đó như thế này:

public static class ExceptionAssert 
{ 
    public static T Throws<T>(Action action) where T : Exception 
    { 
    try 
    { 
     action(); 
    } 
    catch (T ex) 
    { 
     return ex; 
    } 
    Assert.Fail("Exception of type {0} should be thrown.", typeof(T)); 

    // The compiler doesn't know that Assert.Fail 
    // will always throw an exception 
    return null; 
    } 
} 

Sau đó, bạn có thể viết một cái gì đó thử nghiệm của bạn như thế này:

[TestMethod] 
public void GetOrganisation_MultipleOrganisations_ThrowsException() 
{ 
    OrganizationList organizations = new Organizations(); 
    organizations.Add(new Organization()); 
    organizations.Add(new Organization()); 

    var ex = ExceptionAssert.Throws<CriticalException>(
      () => organizations.GetOrganization()); 
    Assert.AreEqual(MyRes.MultipleOrganisationsNotAllowed, ex.Message); 
} 

này cũng có những lợi ích mà nó xác nhận rằng các ngoại lệ được ném trên đường bạn đang mong đợi nó được ném thay vì bất cứ nơi nào trong phương pháp thử nghiệm của bạn.

+4

cách để đi !!! Tôi thích cách này nhiều hơn. – argatxa

+1

Câu trả lời là gì! Tuyệt vời. Nó đã giúp tôi quá :) – Learner

+0

Giải pháp tuyệt vời mà làm việc cho tôi. –

13

Đối số thư ExpectedException không khớp với thông báo ngoại lệ. Thay vào đó là thông điệp được in trong kết quả kiểm tra nếu ngoại lệ dự kiến ​​không xảy ra.

0

Tôi đã xem qua câu hỏi này trong khi cố gắng tự giải quyết vấn đề tương tự. (Tôi sẽ trình bày chi tiết giải pháp mà tôi đã giải quyết ở bên dưới.)

Tôi phải đồng ý với ý kiến ​​của Gishu về việc quốc tế hóa các thông báo ngoại lệ là một mùi mã.

Tôi đã thực hiện việc này ban đầu trong dự án của riêng mình để tôi có thể có sự nhất quán giữa các thông báo lỗi được gửi bởi ứng dụng của tôi và trong các bài kiểm tra đơn vị của tôi. tức là, chỉ phải xác định các thông báo ngoại lệ của tôi ở một nơi và vào lúc đó, tệp Tài nguyên có vẻ như một nơi hợp lý để làm điều này vì tôi đã sử dụng nó cho nhiều nhãn và chuỗi khác nhau (và vì nó có ý nghĩa để thêm tham chiếu cho nó trong mã thử nghiệm của tôi để xác minh rằng những nhãn tương tự được hiển thị ở những nơi thích hợp). Tại một thời điểm tôi đã xem xét (và thử nghiệm) bằng cách sử dụng các khối try/catch để tránh yêu cầu của một hằng số bởi thuộc tính ExpectedException, nhưng điều này có vẻ như nó sẽ dẫn đến khá nhiều mã bổ sung nếu được áp dụng trên một lớn tỉ lệ.

Cuối cùng, giải pháp mà tôi đã giải quyết là tạo một lớp tĩnh trong thư viện tài nguyên của tôi và lưu trữ các thông báo ngoại lệ của tôi trong đó. Bằng cách này, không cần phải quốc tế hóa chúng (mà tôi đồng ý không có ý nghĩa) và chúng có thể truy cập được bất cứ lúc nào mà một chuỗi tài nguyên có thể truy cập được vì chúng nằm trong cùng một không gian tên. (Điều này phù hợp với mong muốn của tôi không làm cho xác minh các văn bản ngoại trừ một quá trình phức tạp.)

mã kiểm tra của tôi sau đó chỉ cần nắm để (tha thứ các mangling ...):

[Test, 
    ExpectedException(typeof(System.ArgumentException), 
    ExpectedException=ProductExceptionMessages.DuplicateProductName)] 
public void TestCreateDuplicateProduct() 
{ 
    _repository.CreateProduct("TestCreateDuplicateProduct"); 
    _repository.CreateProduct("TestCreateDuplicateProduct"); 
} 
Các vấn đề liên quan