2012-01-10 26 views
10

Đây là lần đầu tiên tôi làm bài kiểm tra đơn vị, vì vậy hãy kiên nhẫn với tôi.
I'm still trying to unit test a library that converts lists of POCOs to ADO.Recordsets. Ngay bây giờ, tôi đang cố gắng viết một bài kiểm tra tạo ra List<Poco>, chuyển đổi nó thành Recordset (sử dụng phương pháp tôi muốn kiểm tra) và sau đó kiểm tra xem chúng có chứa cùng thông tin (như, nếu Poco.Foo == RS.Foo và Sớm...).Làm cách nào để tránh nhiều lần khẳng định trong thử nghiệm đơn vị này?

Đây là POCO:

public class TestPoco 
{ 
    public string StringValue { get; set; } 
    public int Int32Value { get; set; } 
    public bool BoolValue { get; set; } 
} 

... và đây là thử nghiệm cho đến nay (Tôi đang sử dụng xUnit.net):

[Fact] 
public void TheTest() 
{ 
    var input = new List<TestPoco>(); 
    input.Add(new TestPoco { BoolValue = true, Int32Value = 1, StringValue = "foo" }); 

    var actual = input.ToRecordset(); 

    Assert.Equal(actual.BoolValue, true); 
    Assert.Equal(actual.Int32Value, 1); 
    Assert.Equal(actual.StringValue, "foo"); 
} 

Những gì tôi không thích về đây là ba sự khẳng định ở cuối, mỗi một thuộc tính của POCO.
Tôi đã đọc rất nhiều lần rằng nhiều xác nhận trong một thử nghiệm là điều xấu (và tôi hiểu lý do tại sao và tôi đồng ý).

Vấn đề là, làm thế nào tôi có thể loại bỏ chúng?

Tôi có cuốn sách tuyệt vời Roy Osherove của "The Art of Unit Testing" ngay trước mặt tôi, và anh ta có một ví dụ trong đó bao gồm chính xác này (đối với những người có cuốn sách: Chương 7.2.6, trang 202/203):

Trong ví dụ của mình, phương thức được thử trả về một đối tượng AnalyzedOutput với một số thuộc tính và anh ta muốn khẳng định tất cả các thuộc tính để kiểm tra xem mỗi thuộc tính có chứa giá trị mong đợi hay không.

Giải pháp trong trường hợp này:
Tạo một AnalyzedOutput dụ, điền vào nó với các giá trị mong đợi và khẳng định nếu nó tương đương với một trả về bởi phương pháp thử (và ghi đè Equals() để có thể làm được điều này).

Nhưng tôi nghĩ rằng tôi không thể làm điều này trong trường hợp của tôi, bởi vì phương pháp mà tôi muốn thử nghiệm trả về một ADODB.Recordset.

Và để tạo một Recordset với các giá trị dự kiến, đầu tiên tôi sẽ cần phải tạo ra nó hoàn toàn từ đầu:

// this probably doesn't actually compile, the actual conversion method 
// doesn't exist yet and this is just to show the idea 

var expected = new ADODB.RecordsetClass(); 
expected.Fields.Append("BoolValue", ADODB.DataTypeEnum.adBoolean); 
expected.Fields.Append("Int32Value", ADODB.DataTypeEnum.adInteger); 
expected.Fields.Append("StringValue", ADODB.DataTypeEnum.adVarWChar); 

expected.AddNew(); 
expected.BoolValue = true; 
expected.Int32Value = 1; 
expected.StringValue = "foo"; 
expected.Update(); 

Tôi không thích điều này một trong hai, bởi vì đây là cơ bản là một sự trùng lặp của một số của các mã trong phương pháp chuyển đổi thực tế (phương pháp được thử nghiệm), đó là một điều khác để tránh trong các thử nghiệm.

Vì vậy, tôi có thể làm gì bây giờ?
Mức độ trùng lặp này vẫn có thể chấp nhận được trong tình huống đặc biệt này hay không hoặc có cách nào tốt hơn để kiểm tra điều này không?

+8

đó là lý do tại sao "nghệ thuật" của thử nghiệm đơn vị chứ không phải "khoa học" ... – Berryl

+0

Nhiều xác nhận trong một trường hợp thử nghiệm không phải là điều xấu. Ý tưởng cho rằng mỗi trường hợp thử nghiệm chỉ nên có một khẳng định [là ngu xuẩn] (http://stackoverflow.com/a/20300843/545127). – Raedwald

Trả lời

8

Tôi muốn cho rằng tinh thần của điều này, điều này là tốt. Lý do mà nhiều xác nhận là "ác", nếu tôi nhớ lại chính xác, là nó ngụ ý rằng bạn đang thử nghiệm nhiều thứ trong một thử nghiệm. Trong trường hợp này, bạn đang thực sự làm điều đó trong đó bạn đang thử nghiệm từng lĩnh vực, có lẽ để đảm bảo điều này làm việc cho một số loại khác nhau. Vì đó là tất cả một thử nghiệm bình đẳng đối tượng sẽ làm anyway, tôi nghĩ rằng bạn đang ở trong rõ ràng.

Nếu bạn thực sự muốn trở thành chiến binh về nó, hãy viết một bài kiểm tra trên mỗi thuộc tính (j/k!)

6

Nhiều xác nhận trên mỗi đơn vị thử nghiệm hoàn toàn tốt trong sách của tôi, miễn là nhiều xác nhận đều khẳng định cùng một điều kiện thử nghiệm. Trong trường hợp của bạn, họ đang thử nghiệm rằng chuyển đổi đã thành công, vì vậy việc vượt qua bài kiểm tra là có điều kiện đối với tất cả các xác nhận đó là đúng sự thật. Kết quả là, nó hoàn toàn tốt đẹp!

Tôi muốn phân loại "một xác nhận cho mỗi thử nghiệm" làm hướng dẫn chứ không phải quy tắc cứng và nhanh. Khi bạn bỏ qua nó, hãy xem xét lý do tại sao bạn không quan tâm đến nó.

Điều đó nói rằng, cách xung quanh nó là tạo một lớp thử nghiệm duy nhất, trên thiết lập lớp, chạy quá trình thử nghiệm của bạn. Sau đó, mỗi bài kiểm tra chỉ là một xác nhận trên một thuộc tính duy nhất. Ví dụ:

public class ClassWithProperities 
{ 
    public string Foo { get; set; } 
    public int Bar { get; set; } 
} 

public static class Converter 
{ 
    public static ClassWithProperities Convert(string foo, int bar) 
    { 
     return new ClassWithProperities {Foo=foo, Bar=bar}; 
    } 
} 
[TestClass] 
public class PropertyTestsWhenFooIsTestAndBarIsOne 
{ 
    private static ClassWithProperities classWithProperties; 

    [ClassInitialize] 
    public static void ClassInit(TestContext testContext) 
    { 
     //Arrange 
     string foo = "test"; 
     int bar = 1; 
     //Act 
     classWithProperties = Converter.Convert(foo, bar); 
     //Assert 
    } 

    [TestMethod] 
    public void AssertFooIsTest() 
    { 
     Assert.AreEqual("test", classWithProperties.Foo); 
    } 

    [TestMethod] 
    public void AssertBarIsOne() 
    { 
     Assert.AreEqual(1, classWithProperties.Bar); 
    } 
} 

[TestClass] 
public class PropertyTestsWhenFooIsXyzAndBarIsTwoThousand 
{ 
    private static ClassWithProperities classWithProperties; 

    [ClassInitialize] 
    public static void ClassInit(TestContext testContext) 
    { 
     //Arrange 
     string foo = "Xyz"; 
     int bar = 2000; 
     //Act 
     classWithProperties = Converter.Convert(foo, bar); 
     //Assert 
    } 

    [TestMethod] 
    public void AssertFooIsXyz() 
    { 
     Assert.AreEqual("Xyz", classWithProperties.Foo); 
    } 

    [TestMethod] 
    public void AssertBarIsTwoThousand() 
    { 
     Assert.AreEqual(2000, classWithProperties.Bar); 
    } 
} 
+0

Thực sự thích cách tiếp cận của bạn! – TuomasK

2

Những 3 khẳng định là hợp lệ. Nếu bạn đã sử dụng một khung giống như mspec, nó sẽ trông giống như:

public class When_converting_a_TestPoco_to_Recordset 
{ 
    protected static List<TestPoco> inputs; 
    protected static Recordset actual; 

    Establish context =() => inputs = new List<TestPoco> { new TestPoco { /* set values */ } }; 

    Because of =() => actual = input.ToRecordset(); 

    It should_have_copied_the_bool_value =() => actual.BoolValue.ShouldBeTrue(); 
    It should_have_copied_the_int_value =() => actual.Int32Value.ShouldBe (1); 
    It should_have_copied_the_String_value =() => actual.StringValue.ShouldBe ("foo"); 
} 

Tôi thường sử dụng mspec làm điểm chuẩn để xem thử nghiệm của tôi có hợp lý hay không. Các bài kiểm tra của bạn chỉ đọc tốt với mspec, và điều đó mang lại cho tôi một số fuzzies ấm áp bán tự động mà tôi đang thử nghiệm những thứ chính xác.

Đối với vấn đề đó, bạn đã hoàn thành công việc tốt hơn với nhiều xác nhận. Tôi ghét nhìn thấy các thử nghiệm giống như sau:

Assert.That (actual.BoolValue == true && actual.Int32Value == 1 && actual.StringValue == "foo"); 

Vì khi điều đó không thành công, thông báo lỗi "dự kiến ​​Đúng, đã sai" là hoàn toàn vô giá trị. Nhiều xác nhận và sử dụng khung kiểm thử đơn vị càng nhiều càng tốt, sẽ giúp bạn rất nhiều.

3

Tôi đồng ý với tất cả các nhận xét khác rằng việc làm như vậy là tốt, nếu bạn đang kiểm tra một cách hợp lý một điều.

Tuy nhiên, có sự khác biệt giữa có nhiều xác nhận trong một bài kiểm tra đơn vị so với việc có một bài kiểm tra đơn vị riêng biệt cho từng thuộc tính. Tôi gọi nó là 'Chặn xác nhận' (Có lẽ là một tên tốt hơn trên mạng). Nếu bạn có nhiều xác nhận trong một bài kiểm tra thì bạn sẽ chỉ biết về một thất bại trong thuộc tính đầu tiên đã thất bại trong việc xác nhận. Nếu bạn có 10 thuộc tính và 5 trong số đó trả lại kết quả không chính xác thì bạn sẽ phải sửa chữa kết quả đầu tiên, chạy lại kiểm tra và thông báo lỗi khác, sau đó sửa lỗi đó, v.v.

Tùy thuộc vào giao diện của bạn nó có thể khá bực mình. Mặt khác, có 5 đơn vị kiểm tra đơn giản không đột nhiên cũng có thể tắt, nhưng nó có thể cho bạn một bức tranh rõ ràng hơn về những gì đã khiến những người đó thất bại cùng một lúc và có thể hướng bạn nhanh hơn đến một bản sửa lỗi đã biết (có lẽ).

Tôi sẽ nói nếu bạn cần kiểm tra nhiều thuộc tính giữ số xuống (có thể dưới 5) để tránh sự cố xác nhận chặn không thể kiểm soát được. Nếu có một tấn tài sản để kiểm tra thì có lẽ nó là một dấu hiệu cho thấy mô hình của bạn đại diện cho quá nhiều hoặc có lẽ bạn có thể xem xét các thuộc tính nhóm thành nhiều thử nghiệm.

1

Điều này phải là một cái gì đó để kiểm tra http://rauchy.net/oapt/ Công cụ tạo ra một trường hợp thử nghiệm mới cho mọi khẳng định.

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