Có cách viết bài kiểm tra đơn vị nào tốt hơn một loạt 'AssertEquals' không?


12

Đây là một ví dụ cơ bản về những gì bài kiểm tra đơn vị của tôi cần, sử dụng qunit:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>

<link rel="stylesheet" href="qunit/qunit-1.13.0.css">
<script src = "qunit/qunit-1.13.0.js"></script>
<script src = "../js/fuzzQuery.js"></script>

<script>

test("Fuzz Query Basics", function()
        {
            equal(fuzzQuery("name:(John Smith)"), "name:(John~ Smith~)");
            equal(fuzzQuery("name:Jon~0.1"), "name:Jon~0.1");
            equal(fuzzQuery("Jon"), "Jon~");
            //etc

        }
    );

</script>
</head>
<body>
    <div id="qunit"></div>
</body>
</html>

Bây giờ tôi đã nghĩ rằng điều này là một chút lặp đi lặp lại.

Có thể đặt tất cả các đầu vào / đầu ra thành một mảng và lặp qua nó.

test("Fuzz Query Basics", function()
        {
            var equals = [
                           ["name:(John Smith)", "name:(John~ Smith~)"],
                           ["name:Jon~0.1", "name:Jon~0.1"],
                           ["Jon", "Jon~"]
                           ];

            for (var i = 0; i<equals.length; i++)
                {
                    equal(fuzzQuery(equals[i][0]), equals[i][1]);               
                }

        }
    );

Và điều này hoạt động tốt.

Ưu điểm duy nhất tôi có thể nghĩ đến cho phương pháp thứ hai này, là nếu nó thực sự không muốn sử dụng equalthì việc thay đổi đó ở một điểm sẽ dễ dàng hơn.

Về khả năng đọc, tôi không nghĩ đó là kết luận, dù tôi có lẽ thích cái thứ hai hơn.

Tóm tắt thêm, bạn có thể đặt các trường hợp đầu vào / đầu ra vào một tệp CSV riêng biệt, điều này có thể giúp sửa đổi dễ dàng hơn.

Câu hỏi là - các quy ước chung xung quanh việc viết các loại bài kiểm tra đơn vị này là gì?

Có một lý do bạn không nên đặt chúng vào mảng?


Một trong hai sẽ cho bạn biết giá trị nào thất bại?
JeffO

1
@JeffO - Có - Với QUnit - Nếu thử nghiệm thất bại, đầu ra sẽ hiển thị giá trị mong đợi và giá trị thực tế.
dwjohnston

Câu trả lời:


8

Các xét nghiệm tái cấu trúc của bạn có mùi: Logic kiểm tra có điều kiện .

Những lý do bạn nên tránh viết logic có điều kiện trong các bài kiểm tra của mình là hai lần. Đầu tiên là nó làm suy yếu khả năng của bạn để tự tin rằng mã kiểm tra của bạn là chính xác, như được mô tả trong bài viết xUnit Forms được liên kết.

Thứ hai là nó che khuất ý nghĩa của các bài kiểm tra. Chúng tôi viết Phương thức kiểm tra vì họ đặt logic để kiểm tra một hành vi nhất định ở một nơi và cho phép chúng tôi đặt cho nó một tên mô tả (xem bài viết BDD ban đầu của Dan North để khám phá giá trị của tên tốt cho các bài kiểm tra). Khi các bài kiểm tra của bạn được ẩn bên trong một hàm duy nhất với một forvòng lặp, nó sẽ che khuất ý nghĩa của mã cho người đọc. Người đọc không chỉ phải hiểu được vòng lặp, họ còn phải tinh thần làm sáng tỏ tất cả các hành vi khác nhau đang được thử nghiệm trong vòng lặp.

Giải pháp, như mọi khi, là di chuyển lên một mức độ trừu tượng. Sử dụng khung kiểm tra cung cấp cho bạn các thử nghiệm được tham số hóa , như xUnit.NET hoặc Contexts làm (từ chối trách nhiệm: Tôi đã viết Bối cảnh). Điều này cho phép bạn nhóm các thử nghiệm tam giác cho cùng một hành vi theo cách tự nhiên, trong khi giữ các thử nghiệm cho các hành vi riêng biệt riêng biệt.


Nhân tiện, câu hỏi hay
Benjamin Hodgson

1
1) Nếu bạn tăng lên một mức độ trừu tượng, bạn không che giấu những chi tiết rất giống nhau mà bạn nói đang bị che khuất bởi vòng lặp for sao? 2) không chắc chắn các thử nghiệm tham số được áp dụng ở đây. Có vẻ như có sự tương đồng ở đây ở đâu đó, nhưng tôi đã có nhiều tình huống tương tự như OP nơi tôi có bộ dữ liệu gồm 10-20 giá trị và chỉ muốn chạy tất cả chúng thông qua SUT. Có, mỗi giá trị là khác nhau và có khả năng kiểm tra các boudary khác nhau nhưng dường như thực sự xuất hiện các tên thử nghiệm "phát minh" cho mỗi giá trị sẽ là quá mức cần thiết. Tôi đã tìm thấy tỷ lệ giá trị / kích thước mã tối ưu khi sử dụng tương tự ...
DXM

... vòng lặp. Miễn là khi thử nghiệm thất bại, khẳng định sẽ in chính xác những gì thất bại, nhà phát triển có đủ phản hồi để xác định chính xác vấn đề.
DXM

@DXM 1) khung kiểm tra cung cấp chức năng kiểm tra tham số. Chúng tôi hoàn toàn tin tưởng vào khung kiểm tra vì vậy chúng tôi không viết các bài kiểm tra cho nó. 2) các thử nghiệm tham số được thực hiện chính xác cho mục đích này: bạn đang thực hiện chính xác các bước giống nhau mỗi lần nhưng với các giá trị đầu vào / đầu ra khác nhau. Khung kiểm tra giúp bạn tiết kiệm được nhu cầu viết tên cho từng người bằng cách chạy các đầu vào khác nhau thông qua cùng một phương thức kiểm tra.
Benjamin Hodgson

5

Có vẻ như bạn thực sự muốn một bài kiểm tra đơn vị hướng dữ liệu. Vì bạn đã đề cập bằng QUnit, tôi đã tìm thấy một plugin cho phép kiểm tra tham số:

https://github.com/AStepaniuk/qunit-parameterize

Không có gì sai về mặt ý thức hệ với một bài kiểm tra dựa trên dữ liệu, miễn là bản thân mã kiểm tra không có điều kiện. Nhìn vào mã kiểm tra của bạn, nó dường như là một ứng cử viên rất tốt cho Bài kiểm tra hướng dữ liệu.

Mã ví dụ cho GitHub README:

QUnit
    .cases([
        { a : 2, b : 2, expectedSum : 4 },
        { a : 5, b : 5, expectedSum : 10 },
        { a : 40, b : 2, expectedSum : 42 }
    ])
    .test("Sum test", function(params) {
        var actualSum = sum(params.a, params.b);
        equal(actualSum, params.expectedSum);
    });

1
Đồng ý, nó trông giống như một bài kiểm tra dựa trên dữ liệu. Nhưng có vẻ như đó là những gì anh ta đã có trong ví dụ mã thứ hai của mình.
Robert Harvey

1
@RobertHarvey - Đúng. Có một thuật ngữ được chấp nhận cho những gì anh ta đang cố gắng thực hiện và một plugin tồn tại cho khung thử nghiệm đang được sử dụng để giúp viết các loại thử nghiệm này dễ dàng hơn. Tôi nghĩ rằng nó đáng chú ý trong một câu trả lời cho tương lai, đó là tất cả.
Greg Burghardt

1

Bạn đang lặp lại bản thân ít hơn bằng cách sử dụng mảng có thể duy trì nhiều hơn. Một cách tiếp cận tôi muốn sử dụng là có một phương pháp riêng để sắp xếp, hành động và xác nhận các thử nghiệm, nhưng chấp nhận các tham số đầu vào mà tôi đang thử nghiệm để tôi có 1 phương thức thử nghiệm cho mỗi bộ đầu vào.

Điều này cho phép tôi ngay lập tức cho biết thử nghiệm / đầu vào nào bị lỗi.


0

Tôi thích cách tiếp cận thứ hai của bạn, nhưng tôi sẽ thêm 2 Điểm

  • không sử dụng mảng để lưu trữ dữ liệu đã kiểm tra, vì làm việc với các chỉ mục là một cách không sạch
  • không sử dụng forcác vòng lặp

`

[
    {
        process: "name:(John Smith)",
        result: "name:(John~ Smith~)"
    },
    {
        process: "name:Jon~0.1", 
        result: "name:Jon~0.1"
    },
    {
        process: "Jon", 
        result: "Jon~"
    }
]
.forEach(function(data){

    var result = fuzzQuery(data.process);
    equal(result, data.result);
});

Tôi không chắc chắn về qunit, nhưng một người chạy thử nghiệm tốt sẽ cho bạn thấy chuỗi đầu vào nào thất bại và kết quả mong đợi là gì

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.