Có bất kỳ giá trị nào khi viết một bài kiểm tra đơn vị là tập hợp con của bài kiểm tra khác không?


15

Để đưa ra một ví dụ hơi khó hiểu, giả sử tôi muốn kiểm tra rằng một hàm trả về hai số và số thứ nhất nhỏ hơn số thứ hai:

def test_length():
    result = my_function()
    assert len(result) == 2

def test_order()
    a, b = my_function()
    assert a < b

Ở đây, nếu test_lengththất bại, thì test_ordercũng sẽ thất bại. Nó là một thực hành tốt nhất để viết test_length, hoặc bỏ qua nó?

EDIT: lưu ý rằng trong tình huống này, cả hai bài kiểm tra hầu hết đều độc lập với nhau, mỗi bài kiểm tra có thể được chạy riêng rẽ hoặc chúng có thể được chạy theo thứ tự ngược lại, điều này không thành vấn đề. Vì vậy, không có câu hỏi trước đây

là một bản sao của một ở trên.



2
@ GlenH7 - đây có vẻ là một câu hỏi khác. Khác là "nếu bạn có các chức năng trong đó Acác cuộc gọi Bvà trả về cùng một kết quả, bạn nên kiểm tra cả hai AB". Đây là nhiều hơn về các bài kiểm tra chồng chéo thay vì (các) chức năng được kiểm tra. (Mặc dù nó khó hiểu vì chúng hiện đang được đặt tên).
Telastyn


1
Nói một cách nghiêm túc những bài kiểm tra này không thực sự chồng chéo (chúng không phụ thuộc thành công). Một hàm lambda: type('', (), {'__len__': lambda self: 2})()sẽ vượt qua hàm thứ nhất, nhưng không phải hàm thứ hai.
liori

1
@ GlenH7: FWIW, tôi không thực sự thay đổi câu hỏi, chỉ cố gắng làm cho nó an toàn ;-) (@gnat: không xúc phạm, chỉ đùa thôi!)
Doc Brown

Câu trả lời:


28

Có thể có giá trị, nhưng đây là một chút mùi. Các bài kiểm tra của bạn không bị cô lập tốt (vì test_orderthực sự kiểm tra hai điều) hoặc bạn quá giáo điều trong bài kiểm tra của mình (thực hiện hai bài kiểm tra kiểm tra cùng một điều hợp lý).

Trong ví dụ này, tôi sẽ hợp nhất hai bài kiểm tra với nhau. Vâng, nó có nghĩa là bạn có nhiều khẳng định. Quá tệ. Bạn vẫn đang thử nghiệm một điều duy nhất - kết quả của chức năng. Đôi khi trong thế giới thực có nghĩa là thực hiện hai kiểm tra.


Tôi nêu lên câu trả lời của bạn mặc dù nó bỏ lỡ một điểm nhỏ. Trong Python, thử nghiệm thứ hai cũng sẽ thất bại khi my_functionkhông trả về chính xác hai giá trị, mà không có bất kỳ khẳng định nào - bởi vì việc gán sẽ dẫn đến một ngoại lệ. Vì vậy, thực sự không cần phải sử dụng nhiều khẳng định và hai kiểm tra để kiểm tra cùng một thứ.
Doc Brown

@DocBrown - Tôi đã giả sử nhiều, nhưng tôi không quen với các thông báo lỗi của Python để biết liệu có thể có giá trị khi có lỗi xác nhận thay vì ngoại lệ / lỗi ngẫu nhiên vì lý do thông tin hay không.
Telastyn

Tôi nghĩ rằng trong tình hình hiện tại, thông báo lỗi có thể đủ thông tin. Nhưng nói chung, đó có thể không phải là trường hợp. Đó là lý do tại sao tôi đồng ý với bạn rằng cách tiếp cận chung cho một trường hợp như thế này nên nghĩ đến việc "hợp nhất", sử dụng hai khẳng định. Nếu nó chỉ ra rằng thử nghiệm có thể được đơn giản hóa hơn nữa bằng cách loại bỏ một trong những khẳng định, tốt thôi.
Doc Brown

5
@DocBrown Giá trị khác trong việc kiểm tra rõ ràng với một khẳng định là nó trở nên rõ ràng đối với bất kỳ ai kiểm tra bài kiểm tra rằng đây là lỗi của mã đang kiểm tra chứ không phải bản thân bài kiểm tra. Khi các bài kiểm tra của tôi gặp phải trường hợp ngoại lệ không mong muốn, tôi luôn phải dành thời gian để tìm ra cái nào thực sự sai.
Chris Hayes

@ChrisHayes: Tôi đã viết "không có nhu cầu", không phải "không có giá trị" trong đó.
Doc Brown

5

Các xét nghiệm của bạn nên rõ ràng. Nó không hoàn toàn suy ra rằng nếu text_length không thành công thì test_order không thành công.

Tôi không chắc nó hoạt động như thế nào trong Python mà bạn đã đăng, nhưng nếu len(result)là 3 thì lần đầu tiên sẽ thất bại nhưng lần thứ hai có thể vượt qua (và nếu không phải bằng Python, thì chắc chắn là các ngôn ngữ như JavaScript).

Giống như bạn đã nói, bạn muốn kiểm tra hàm trả về hai số và chúng có theo thứ tự không. Hai bài kiểm tra đó là.


1
It's not completely inferred that if text_length fails test_order fails- trong Python, nó sẽ cung cấp cho bạn một ngoại lệ.
Doc Brown

Tôi nghĩ rằng câu hỏi là về trường hợp thất bại test_lengthngụ ý thất bại test_order. Việc một cặp thử nghiệm tương tự được viết bằng Javascript sẽ không hoạt động giống như hai thử nghiệm python này là không liên quan.
Dawood nói phục hồi Monica

2
@DavidWallace: hãy nhớ rằng, câu hỏi là "Đó là cách tốt nhất để viết test_length hay bỏ qua nó"? Trong Javascript, bạn cần cả hai bài kiểm tra để đảm bảo bạn không bỏ sót vấn đề nào (khi bạn không hợp nhất hai bài kiểm tra thành một). Trong Python, bạn có thể bỏ qua câu đầu tiên một cách an toàn (bị từ chối trong câu đầu tiên của câu trả lời này và được tuyên bố là "Tôi không chắc chắn" trong câu thứ hai). Thành thật mà nói, một câu trả lời tốt có vẻ khác nhau. Tuy nhiên, tôi đã không đánh giá thấp câu trả lời này vì phần hay thực sự là đề cập đến JavaScript.
Doc Brown

4
@DavidWallace: vì chúng tôi ở đây là một lập trình viên.com, không phải trên stackoverflow.com, IMHO đưa ra câu trả lời có thể áp dụng cho nhiều ngôn ngữ tốt hơn là chỉ trả lời cho một ngôn ngữ cụ thể. Nhưng khi đề cập đến một ngôn ngữ cụ thể, câu trả lời phải chính xác về ngôn ngữ và không trộn lẫn một số thuộc tính.
Doc Brown

1
Điều quan trọng là, câu hỏi là "có đáng để viết một bài kiểm tra là một tập hợp con của bài kiểm tra khác không" và câu trả lời này nói, "trong một số ngôn ngữ, cả hai bài kiểm tra của bạn đều không phải là tập hợp của bài kiểm tra khác" và sau đó đi đến kết luận cả hai bài kiểm tra là do đó cần thiết Nó đọc cho tôi như thể ai đó nói, "mã của bạn hoàn toàn không biên dịch trong C ++ và bên cạnh đó, trong C ++, một hàm chỉ có thể trả về một giá trị nên bạn không cần kiểm tra nó trả về hai. Chỉ viết một bài kiểm tra" ;-)
Steve Jessop

2

Giá trị duy nhất test_lengthở đây là, nếu mọi thứ trôi qua, chính sự hiện diện của nó cho thấy "độ dài" đã được kiểm tra.

Vì vậy, thực sự không cần thiết phải có cả hai bài kiểm tra này. Chỉ giữ test_orderlại nhưng xem xét đổi tên nó test_length_and_order.

Tình cờ, tôi thấy việc sử dụng tên bắt đầu bằng testmột chút vụng về. Tôi là một người ủng hộ mạnh mẽ các tên thử nghiệm thực sự mô tả tình trạng mà bạn đang khẳng định.


1
Các testmụn cóc có ý nghĩa để khuôn khổ kiểm tra của Python. Tất nhiên điều đó không cần thay đổi cho dù bạn có phải là fan hâm mộ của nó hay không, nhưng có thay đổi trọng số của lập luận cần thiết để ngăn chặn ai đó sử dụng nó hay không ;-)
Steve Jessop

@SteveJessop Vâng, tôi tiếp tục quên rằng nó cần thiết. Khi tôi đang viết các bài kiểm tra Python cách đây một thời gian, tôi đã có thói quen bắt đầu tất cả chúng bằng test_that_, như thế test_that_return_values_are_in_ordervà cứ thế. Có thể một phiên bản tương lai của khung thử nghiệm sẽ hoạt động xung quanh yêu cầu này bằng cách nào đó.
Dawood nói phục hồi Monica

@DavidWallace: bạn có thể thay đổi tiền tố nếu bạn muốn.
Lie Ryan

1

Tôi sẽ để các thử nghiệm này tách biệt nếu đó là cách chúng đã phát triển. Có test_orderkhả năng thất bại bất cứ khi nào test_length, nhưng bạn chắc chắn biết tại sao.

Tôi cũng đồng ý rằng nếu test_orderlần đầu tiên xuất hiện và bạn thấy lỗi không thể kiểm tra được thì kết quả có thể không phải là hai giá trị, thêm kiểm tra đó dưới dạng assertvà đổi tên thử nghiệm thành test_length_and_ordercó ý nghĩa.

Nếu bạn cũng phải kiểm tra các loại giá trị được trả về là số nguyên, tôi sẽ đưa nó vào kiểm tra kết quả "omnibus" này.

Nhưng lưu ý bây giờ bạn có một loạt các bài kiểm tra cho kết quả của my_function() . Nếu có nhiều bối cảnh (hoặc, nhiều khả năng, nhiều tham số) để kiểm tra thì bây giờ có thể là chương trình con để kiểm tra tất cả các kết quả từ đó my_function().

Tuy nhiên, khi tôi viết các bài kiểm tra đơn vị, tôi thường kiểm tra các trường hợp cạnh và trường hợp xấu tách biệt với đầu vào tốt và đầu ra bình thường (một phần vì hầu hết các bài kiểm tra "đơn vị" của tôi thường là các bài kiểm tra tích hợp nhỏ) và thường có nhiều xác nhận, chỉ bị hỏng vào các thử nghiệm riêng biệt nếu chúng thất bại theo cách tôi tìm thấy tôi muốn biết thêm thông tin mà không cần gỡ lỗi.

Vì vậy, tôi có thể sẽ bắt đầu với các thử nghiệm riêng biệt của bạn và mở rộng test_lengthsang test_length_and_typesvà để test_orderriêng, giả sử cái sau được coi là "xử lý bình thường".

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.