2011-01-24 27 views
12

Tôi đăng câu hỏi này một lần nữa theo chỉ thị của John Skeet phân biệt, người đề nghị tôi đưa ra một chương trình thử nghiệm đơn giản mà cô lập và chứng minh vấn đề tôi đang gặp phải và đăng lại câu hỏi. Câu hỏi này phát triển từ this one, vì vậy hãy tha thứ cho tôi nếu mọi thứ nghe rất quen thuộc. Bạn có khả năng thu thập thêm chi tiết về câu hỏi này từ câu hỏi đó.NUnit: Tại sao không khẳng định.Thủ số <T> Ghi nhận xét ArgumentNullException của tôi?

Vấn đề tôi đang gặp phải liên quan đến Assert.Throws<T> từ NUnit 2.5.9. Đôi khi, sẽ không bắt được bất kỳ ngoại lệ nào được ném trong phương thức được gọi bởi TestDelegate. Tôi đã ghim hành vi này theo cách lặp lại trong mã bên dưới. . (Mặc dù điều này có thể, phải thừa nhận, là một trường hợp không thành công trên máy của tôi ™

Để sao chép các lỗi, tôi đã tạo ra một giải pháp với các dự án # DLL hai C:

  • Đầu tiên chứa một lớp, Phương pháp đó là một phương thức công khai, là phương thức mở rộng đóng gói logic cần thiết để tạo ra một số SqlCommand, điền các tham số của nó và gọi ra các tham số của nó và gọi số ExecuteScalar trên đó. kiểm tra xem phương thức trong DLL đầu tiên có hoạt động như dự kiến ​​hay không. eference cho NUnit Framework. Không có hội đồng nào khác được tham chiếu.

Khi tôi bước qua các bài kiểm tra trong trình gỡ lỗi, tôi quan sát như sau:

  1. Assert.Throws gọi một cách chính xác các phương pháp ExecuteScalar<T> mở rộng.
  2. Giá trị tham số là null, như mong đợi.
  3. ExecuteScalar<T> kiểm tra thông số của nó cho giá trị null.
  4. Trình gỡ lỗi thực hiện và thực thi dòng có chứa throw new ArgumentNullException(...).
  5. Sau khi thực hiện throw, kiểm soát ứng dụng không được chuyển ngay đến Assert.Throws. Thay vào đó, nó tiếp tục trên dòng tiếp theo trong ExecuteScalar<T>.
  6. Ngay sau khi dòng mã tiếp theo thực hiện, trình gỡ lỗi ngắt và hiển thị lỗi "Ngoại lệ null đối số đã bị hủy bởi mã người dùng".

Mã nguồn tách biệt hành vi này được đưa ra dưới đây.

GIA HẠN PHƯƠNG PHÁP

namespace NUnit_Anomaly 
{ 
    using System; 
    using System.Data; 
    using System.Data.SqlClient; 

    public static class Class1 
    { 
     public static T ExecuteScalar<T>(this SqlConnection connection, string sql) 
     { 
      if (connection == null) 
      { 
       throw new ArgumentNullException("connection"); 
      } 

      if (sql == null) 
      { 
       throw new ArgumentNullException("sql"); 
      } 

      using (var command = connection.CreateCommand()) 
      { 
       command.CommandType = CommandType.Text; 
       command.CommandText = sql; 
       return (T)command.ExecuteScalar(); 
      } 
     } 
    } 
} 

test

namespace NUnit_Tests 
{ 
    using System; 
    using System.Data.SqlClient; 
    using System.Diagnostics; 

    using NUnit.Framework; 

    using NUnit_Anomaly; 

    [TestFixture] 
    public class NUnitAnomalyTest 
    { 

     [Test] 
     public void ExecuteDataSetThrowsForNullConnection() 
     { 
      Assert.Throws<ArgumentNullException>(() => ((SqlConnection)null).ExecuteScalar<int>(null)); 
     } 

     [Test] 
     public void ExecuteDataSetThrowsForNullSql() 
     { 

      const string server = "MY-LOCAL-SQL-SERVER"; 
      const string instance = "staging"; 
      string connectionString = String.Format("Data Source={0};Initial Catalog={1};Integrated Security=True;", 
                server, 
                instance); 

      using (var connection = new SqlConnection(connectionString)) 
      { 
       Assert.Throws<ArgumentNullException>(() => connection.ExecuteScalar<int>(null)); 
      } 
     } 
    } 
} 

Hiệu quả cuối cùng là các bài kiểm tra thất bại khi họ không nên. Theo sự hiểu biết tốt nhất của tôi, Assert.Throws<T> sẽ bắt ngoại lệ của tôi và thử nghiệm sẽ vượt qua.

CẬP NHẬT

tôi đã tư vấn Hans' và kiểm tra hộp thoại Exceptions. Tôi đã không vi phạm các trường hợp ngoại lệ ném, nhưng tôi đã vi phạm trên người dùng chưa được xử lý ngoại lệ. Rõ ràng, đó là lý do tại sao trình gỡ lỗi xâm nhập vào IDE khi ngoại lệ được ném. Xóa hộp kiểm đã khắc phục được sự cố và Assert.Throws<T> chọn nó. Tuy nhiên, nếu tôi đã không làm điều này, tôi không thể chỉ cần nhấn F5 để tiếp tục thực hiện, hoặc trường hợp ngoại lệ sẽ trở thành một NullReferenceException.

Vì vậy, bây giờ câu hỏi là: Tôi có thể định cấu hình các vi phạm ngoại lệ trên cơ sở từng dự án không? Tôi chỉ muốn làm điều này khi tôi đang thử nghiệm, nhưng không phải nói chung.

+1

Gỡ lỗi + Ngoại lệ, đảm bảo rằng hộp kiểm Đã tắt. –

+0

@Hans Passant: Tôi đã xác minh rằng không có hộp kiểm Thrown nào được chọn. –

Trả lời

15

Điều gì thực sự xảy ra là Assert.Throwskhông bắt ngoại lệ của bạn, tuy nhiên Visual Studio dừng trên đầu cơ hội ngoại lệ nào. Bạn có thể kiểm tra điều này bằng cách nhấn F5; Visual Studio sẽ vui vẻ thực hiện.

Là người trợ giúp ngoại lệ cho bạn biết, ngoại lệ đã bị hủy theo mã người dùng. Vì vậy, chúng tôi biết rằng Visual Studio không coi NUnit là mã người dùng vì một lý do nào đó.

enter image description here

Visual Studio thực sự nói với bạn điều này trong văn bản đơn giản, nếu bạn biết được nơi để xem xét:

enter image description here

Ngoài ra còn có bằng chứng về sự kiện này trong stack trace:

enter image description here

Giải pháp 1: Sử dụng trình gỡ lỗi NUnit với các biểu tượng gỡ lỗi. Đó là will get Visual Studio to regard NUnit as user code và do đó ngừng xử lý các ngoại lệ của bạn là "không được mã hóa bởi mã người dùng". Đây không phải là tầm thường, nhưng có thể hoạt động tốt hơn trong thời gian dài.

Giải pháp 2: Tắt hộp kiểm "Enable Just My Code" trong cài đặt gỡ lỗi Visual Studio của:

enter image description here

T.B. Tôi không xem xét xung quanh công việc, theo đó bạn tránh sử dụng toàn bộ số Assert.Throws<T>, nhưng tất nhiên là có nhiều cách để thực hiện điều đó.

+0

Tôi đang sử dụng nunit-console.exe và không sử dụng trình gỡ lỗi VS. Tôi thậm chí không chạy mã chế độ gỡ lỗi. Điều này có nghĩa là bất cứ điều gì nếu NUnit không bắt được ngoại lệ của tôi? –

+0

@GrantBirchmeier Bạn có thể gặp sự cố khác, tôi khuyên bạn nên đặt câu hỏi mới và cung cấp thêm chi tiết tại đó. –

+0

Hóa ra đó là lỗi của người dùng, tất cả đều thuộc về tôi. –

Các vấn đề liên quan