2009-01-28 28 views
5

Tôi là một fan hâm mộ lớn của khung công tác xUnit.NET; Tôi thấy nó nhẹ, đơn giản, sạch sẽ và có thể mở rộng.Mở rộng xUnit.NET để sử dụng mã tùy chỉnh khi xử lý một lớp và định vị phương thức thử

Bây giờ chúng ta hãy nói rằng tôi có một lớp học như vậy:

public class AdditionSpecification 
{ 
    static int result; 

    public void Because() 
    { 
    result = 2 + 2; 
    } 

    public void Result_is_non_zero() 
    { 
    Assert.True(result <> 0); 
    } 

    public void Result_is_correct() 
    { 
    Assert.Equal(4, result); 
    } 
} 

Với lớp thử nghiệm trên tôi muốn xUnit.NET để xem 2 trường hợp thử nghiệm và chạy các phương pháp Vì() trước mỗi trong số họ.

Gác lại bất kỳ vấn đề bạn có thể có với tên lớp hoặc phương pháp của tôi, cấu trúc của bài kiểm tra này/đặc điểm kỹ thuật, khuôn khổ xUnit.NET hoặc BDD, đây là câu hỏi của tôi:

Làm thế nào tôi có thể nói xUnit. NET mà tôi muốn tùy chỉnh như thế nào nó xác định và thực hiện các phương pháp kiểm tra ra khỏi lớp này mà không cần bằng cách sử dụng một tùy chỉnh [Fact] giống như thuộc tính trên mỗi phương pháp thử nghiệm mục tiêu?

Tôi biết rằng tôi có thể lấy được từ BeforeAfterAttribute để trang trí từng phương pháp thử với tùy chỉnh trước và sau khi thực thi. Làm thế nào tôi có thể làm điều này ở cấp lớp? Tôi có phải viết một Á hậu tùy chỉnh không?

Trả lời

9

Vì vậy, hóa ra tôi đang tìm phương pháp ITestClassCommand.EnumerateTestMethods().

  1. Á hậu thử nghiệm xUnit.NET mặc định sẽ lặp qua tất cả các lớp trong lắp ráp thử nghiệm của bạn.
  2. Đối với mỗi thiết bị, nó sẽ kiểm tra một RunWithAttribute; đó là cơ hội để bạn ghi đè số Triển khai ITestClassCommand được sử dụng để xác định các phương pháp chứa các thử nghiệm. (RunWithNUnit là một ví dụ tốt)
  3. ITestClassCommand.EnumerateTestMethods() được gọi để xử lý lớp thử nghiệm và trả về một phương thức thử nghiệm IEnumerable.
  4. mỗi bài kiểm tra IMethodInfo sau đó được chuyển cho ITestClassCommand.EnumerateTestCommands (IMethodInfo TestMethod) để có được IEnumerable của ITestCommands
  5. sau đó mỗi ITestCommand được thực hiện và có cơ hội để trở lại một kết quả.

Trong trường hợp ví dụ của tôi ở trên, tôi sẽ cần một cái gì đó như:

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] 
public class RunWithMyTestClassCommandAttribute : RunWithAttribute 
{ 
    public RunWithMyTestClassCommandAttribute() 
       : base(typeof(MyTestClassCommand)) {} 
} 

Sau đó, tôi có thể trang trí ví dụ trên của tôi với:

[RunWithMyTestClassCommand] 
public class AdditionSpecification 
{ 
    static int result; 

    public void Because() 
    { 
    result = 2 + 2; 
    } 

    public void Result_is_non_zero() 
    { 
    Assert.True(result <> 0); 
    } 

    public void Result_is_correct() 
    { 
    Assert.Equal(4, result); 
    } 
} 

Cuối cùng, trong MyTestClassCommand, tôi nhận được để có cơ hội giữa EnumerateTestMethods() và EnumerateTestCommands (IMethodInfo testMethod) để sử dụng bất kỳ logic nào tôi muốn định vị và xây dựng các cá thể ITestCommand được thực hiện dưới dạng các thử nghiệm riêng lẻ.

BTW, trong quá trình nghiên cứu vấn đề này, tôi chạy vào một lỗi nhỏ trong khung xUnit.NET, nơi một IMethodInfo tùy chỉnh được tạo bởi EnumerateTestMethods() không bao giờ xuất hiện trong EnumerateTestCommands (..) vì nó đã được mở và rewrapped bởi các Á hậu thử nghiệm hoặc một trong các nhà máy của nó.

Tôi nộp this issue cho dự án xUnit trên CodePlex và nó đã corrected on May 30th 2009 cho xUnit.NET 1,5 CTP 2

9

IUseFixture của xUnit.net cho phép bạn thực hiện cài đặt cố định. Do đó bạn có thể định nghĩa lớp vật cố của riêng bạn:

public class AdditionFixture : IDisposable 
{ 
    public int Because() 
    { 
    return 2 + 2; 
    } 

    public void Dispose() 
    { 
    //test tear down code 
    }  
} 

lớp thử nghiệm của bạn sau đó có thể thực hiện điều này (với setFixture yêu cầu thực hiện):

public class AdditionSpecification : IUseFixture<AdditionFixture> 
{ 
    int result; 

    public void SetFixture(AdditionFixture Fixture) 
    { 
    result = Fixture.Because(); 
    } 

    [Fact] 
    public void Result_is_non_zero() 
    { 
    Assert.True(result <> 0); 
    } 

    [Fact] 
    public void Result_is_correct() 
    { 
    Assert.Equal(4, result); 
    } 
} 

Á hậu xUnit sẽ tạo ra một trường hợp duy nhất của trận đấu, và chuyển nó vào SetFixture trước khi chạy từng thử nghiệm. Sau khi chạy tất cả các thử nghiệm của bạn, nhân vật sau đó sẽ vứt bỏ vật cố nếu nó thực hiện IDisposable. Tôi hy vọng rằng sẽ giúp!

wiki xUnit trên codeplex có nhiều thông tin hơn, bao gồm một ví dụ hay về cách triển khai IUseFixture để quản lý kết nối cơ sở dữ liệu cho bạn thử nghiệm đồ đạc.

+1

Cảm ơn bạn đã cố gắng để giúp đỡ, nhưng phản ứng này không trả lời những câu hỏi mà tôi hỏi; làm thế nào để tôi nói với xUnit.NET những phương thức nào tôi muốn thực hiện dựa trên một số quy ước mà không sử dụng thuộc tính [Fact]. –

+0

Giải pháp tôi đề xuất đạt được hiệu quả của việc có() được thực thi trước khi chạy thử. Tôi nhận ra rằng tôi vẫn đang sử dụng thuộc tính [Fact] để đạt được điều này. Tôi có thể hỏi tại sao bạn muốn tránh sử dụng [Fact]? – BenA

+0

Để loại bỏ một số buổi lễ từ việc viết các đồ đạc thử nghiệm; nếu tôi tuân theo quy ước để mã hóa đồ đạc thử nghiệm của mình thì tôi có thể mã logic đó vào nhân vật (hoặc vào ITestClassCommand và RunWithAttribute tùy chỉnh) và xóa tất cả các thuộc tính [Fact], do đó làm cho các bài kiểm tra của tôi dễ đọc hơn một chút và nhanh hơn để mã. –

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