Làm thế nào để bạn kiểm tra đơn vị kiểm tra một đơn vị? [đóng cửa]


89

Tôi đang xem webcast của Rob Connerys trên Ứng dụng MVCStoreFront và tôi nhận thấy anh ấy đang thử nghiệm đơn vị ngay cả những thứ trần tục nhất, những thứ như:

public Decimal DiscountPrice
{
   get
   {
       return this.Price - this.Discount;
   }
}

Sẽ có một bài kiểm tra như:

[TestMethod]
public void Test_DiscountPrice
{
    Product p = new Product();
    p.Price = 100;
    p.Discount = 20;
    Assert.IsEqual(p.DiscountPrice,80);
}

Trong khi, tôi chỉ dành cho việc thử nghiệm đơn vị, đôi khi tôi tự hỏi liệu hình thức phát triển đầu tiên thử nghiệm này có thực sự mang lại lợi ích hay không, ví dụ: trong một quy trình thực, bạn có 3-4 lớp phía trên mã của mình (Yêu cầu nghiệp vụ, Tài liệu yêu cầu, Tài liệu kiến ​​trúc) , trong đó quy tắc kinh doanh được xác định thực tế (Giá chiết khấu là Giá - Giảm giá) có thể được xác định sai.

Nếu đó là tình huống, bài kiểm tra đơn vị của bạn không có ý nghĩa gì đối với bạn.

Ngoài ra, thử nghiệm đơn vị của bạn là một điểm thất bại khác:

[TestMethod]
public void Test_DiscountPrice
{
    Product p = new Product();
    p.Price = 100;
    p.Discount = 20;
    Assert.IsEqual(p.DiscountPrice,90);
}

Bây giờ kiểm tra là thiếu sót. Rõ ràng trong một thử nghiệm đơn giản, không có gì to tát, nhưng giả sử chúng tôi đang thử nghiệm một quy tắc kinh doanh phức tạp. Chúng ta đạt được gì ở đây?

Tua nhanh hai năm trong vòng đời của ứng dụng, khi các nhà phát triển bảo trì đang duy trì nó. Bây giờ doanh nghiệp thay đổi quy tắc của nó, và thử nghiệm lại bị lỗi, một số nhà phát triển tân binh sau đó sửa thử nghiệm không chính xác ... chúng ta giờ lại có một điểm thất bại khác.

Tất cả những gì tôi thấy là nhiều điểm có thể xảy ra lỗi hơn, không có lợi nhuận thực sự có lợi, nếu giá chiết khấu sai, nhóm kiểm tra vẫn sẽ tìm ra vấn đề, làm thế nào đơn vị kiểm tra đã cứu được bất kỳ công việc nào?

Tôi còn thiếu gì ở đây? Xin hãy dạy tôi yêu TDD, vì tôi đang rất khó chấp nhận nó là hữu ích cho đến nay. Tôi cũng muốn, vì tôi muốn tiếp tục tiến bộ, nhưng nó không có ý nghĩa gì đối với tôi.

CHỈNH SỬA: Một vài người vẫn đề cập rằng thử nghiệm giúp thực thi thông số kỹ thuật. Theo kinh nghiệm của tôi, thông số kỹ thuật cũng bị sai, thường xuyên hơn không, nhưng có lẽ tôi phải làm việc trong một tổ chức nơi thông số kỹ thuật được viết bởi những người không nên viết thông số kỹ thuật.


5
trong nhiều trường hợp, bài kiểm tra đơn vị thông số kỹ thuật và cả tài liệu nữa!
Steven A. Lowe

32
... và sau đó kiểm tra đơn vị kiểm tra đơn vị của kiểm tra đơn vị ... nhưng còn kiểm tra đơn vị ^ 4 và kiểm tra đơn vị ^ 5 ... aaaaaaaaahhhhhhhhh!
dacracot 28/10/08

14
Không có bất kỳ loại thử nghiệm nào có thể giúp bạn tránh được một thông số kỹ thuật sai.
Bill the Lizard

4
Có ai khác vừa nghe thấy âm thanh như một bàn tay vỗ tay không?
gnovice

9
Tôi nghĩ câu trích dẫn thích hợp là "Tất cả chỉ là những con rùa."
Quinn Taylor

Câu trả lời:


63

Đầu tiên, kiểm tra cũng giống như bảo mật - bạn không bao giờ có thể chắc chắn 100% rằng mình đã nắm được nó, nhưng mỗi lớp sẽ tăng thêm độ tự tin và một khuôn khổ để dễ dàng khắc phục các vấn đề còn tồn tại hơn.

Thứ hai, bạn có thể chia các bài kiểm tra thành các chương trình con mà sau đó chúng có thể được kiểm tra. Khi bạn có 20 bài kiểm tra tương tự, việc tạo một chương trình con (đã kiểm tra) có nghĩa là bài kiểm tra chính của bạn là 20 lệnh gọi đơn giản của chương trình con có nhiều khả năng đúng hơn.

Thứ ba, một số người cho rằng TDD giải quyết mối quan tâm này. Có nghĩa là, nếu bạn chỉ viết 20 bài kiểm tra và chúng vượt qua, bạn không hoàn toàn tự tin rằng chúng thực sự đang kiểm tra bất cứ thứ gì. Nhưng nếu mỗi bài kiểm tra bạn viết ban đầu không thành công và sau đó bạn sửa nó, thì bạn sẽ tự tin hơn nhiều rằng nó thực sự đang kiểm tra mã của bạn. IMHO qua lại này mất nhiều thời gian hơn đáng giá, nhưng đó là một quá trình cố gắng giải quyết mối quan tâm của bạn.


2
Để chơi người ủng hộ quỷ, tôi thấy các lớp bổ sung càng có nhiều điểm thất bại hơn, điều đó không làm tăng sự tự tin cho tôi. Trong công việc thực tế của mình, tôi làm việc với nhiều nhóm trong một doanh nghiệp SOA có tính phân tán cao. Mỗi đội trong số đó có thể gây nguy hiểm cho dự án nếu lớp của họ không thành công.
FlySwat 28/10/08

2
Đó là lý do tại sao bạn đang sử dụng các đối tượng giả để kiểm tra từng lớp riêng biệt.
Toon Krijthe 28/10/08

10
Tuyệt vời, vì vậy bài kiểm tra của tôi sẽ vượt qua bằng cách sử dụng IMockedComplexObject nhưng khi tôi thực sự sử dụng ComplexObject trong thế giới thực, nó không thành công ... Tôi không thu được gì nữa.
FlySwat 28/10/08

16
@Jonathan - không, bạn đã tự tin rằng mã của mình hoạt động - giả sử rằng bạn đã phát triển lên giao diện của ComplexObject và được thử nghiệm đầy đủ dựa trên giao diện đó. Tệ nhất, bạn đã có được kiến ​​thức rằng sự hiểu biết của bạn về ComplexObject không như những gì bạn mong đợi.
tvanfosson

9
@FlySwat: Đáp lại nhận xét của bạn về IMockedComplexObject, tôi trích dẫn nhận xét của Cwash về một câu trả lời khác: "Bạn không chế nhạo những gì bạn đang cố gắng kiểm tra, bạn chế nhạo những gì bạn không cố gắng kiểm tra."
Brian

39

Một thử nghiệm sai không có khả năng phá vỡ mã sản xuất của bạn. Ít nhất, không tệ hơn là không có bài kiểm tra nào cả. Vì vậy, nó không phải là "điểm thất bại": các bài kiểm tra không cần phải chính xác để sản phẩm thực sự hoạt động. Chúng có thể phải chính xác trước khi được ký là hoạt động, nhưng quá trình khắc phục mọi thử nghiệm bị hỏng không gây nguy hiểm cho mã triển khai của bạn.

Bạn có thể coi các bài kiểm tra, thậm chí là các bài kiểm tra tầm thường như thế này, là một ý kiến ​​thứ hai về những gì mã phải làm. Một ý kiến ​​là kiểm tra, khác là thực hiện. Nếu họ không đồng ý, thì bạn biết bạn có vấn đề và bạn tìm hiểu kỹ hơn.

Nó cũng hữu ích nếu ai đó trong tương lai muốn triển khai cùng một giao diện từ đầu. Họ không cần phải đọc lần triển khai đầu tiên để biết Giảm giá có nghĩa là gì và các bài kiểm tra hoạt động như một bản sao lưu rõ ràng cho bất kỳ mô tả bằng văn bản nào về giao diện mà bạn có thể có.

Điều đó nói rằng, bạn đang đánh đổi thời gian. Nếu có những bài kiểm tra khác mà bạn có thể viết bằng thời gian bạn tiết kiệm được khi bỏ qua những bài kiểm tra tầm thường này, có thể chúng sẽ có giá trị hơn. Nó thực sự phụ thuộc vào thiết lập thử nghiệm của bạn và bản chất của ứng dụng. Nếu Giảm giá là quan trọng đối với ứng dụng, thì bạn vẫn sẽ bắt gặp bất kỳ lỗi nào trong phương pháp này trong thử nghiệm chức năng. Tất cả những gì kiểm tra đơn vị làm là cho phép bạn nắm bắt chúng tại thời điểm bạn đang kiểm tra đơn vị này, khi vị trí của lỗi sẽ hiển thị ngay lập tức, thay vì đợi cho đến khi ứng dụng được tích hợp với nhau và vị trí của lỗi thể ít rõ ràng hơn.

Nhân tiện, cá nhân tôi sẽ không sử dụng 100 làm giá trong trường hợp thử nghiệm (hoặc đúng hơn, nếu tôi làm vậy thì tôi sẽ thêm một thử nghiệm khác với giá khác). Lý do là ai đó trong tương lai có thể nghĩ rằng Giảm giá được cho là một tỷ lệ phần trăm. Một mục đích của những bài kiểm tra tầm thường như thế này là để đảm bảo rằng những sai lầm trong việc đọc thông số kỹ thuật được sửa chữa.

[Liên quan đến việc chỉnh sửa: Tôi nghĩ rằng không thể tránh khỏi việc một thông số kỹ thuật không chính xác là một điểm thất bại. Nếu bạn không biết ứng dụng phải làm gì, thì rất có thể nó sẽ không làm được. Nhưng việc viết các bài kiểm tra để phản ánh thông số kỹ thuật không phóng đại vấn đề này, nó chỉ đơn thuần là không giải quyết được nó. Vì vậy, bạn không thêm các điểm lỗi mới, bạn chỉ thể hiện các lỗi hiện có trong mã thay vì tài liệu waffle .]


4
Một thử nghiệm sai sẽ làm cho mã bị hỏng vào tự nhiên. Đó là nơi mà sự thất bại được giới thiệu. Nó cung cấp một cảm giác tự tin sai lầm.
FlySwat 28/10/08

9
Điều đó đúng, nhưng không có kiểm tra cũng để xảy ra lỗi mã. Sai lầm là nghĩ rằng nếu mã vượt qua thử nghiệm đơn vị thì nó phải chính xác - tôi đã chữa khỏi điều đó khá sớm trong sự nghiệp của mình. Vì vậy, một thử nghiệm đơn vị bị hỏng không cho phép mã bị hỏng ra ngoài tự nhiên, nó chỉ đưa nó vào thử nghiệm tích hợp.
Steve Jessop 28/10/08

7
Ngoài ra, ngay cả một bài kiểm tra sai cũng có thể bắt gặp mã bị hỏng, miễn là nó chứa các lỗi khác nhau từ việc triển khai. Đó là quan điểm của tôi rằng các bài kiểm tra không nhất thiết phải chính xác, chúng ở đó để thu hút sự chú ý của bạn đến các lĩnh vực quan tâm.
Steve Jessop 28/10/08

2
câu trả lời rất thú vị.
Peter

22

Tất cả những gì tôi thấy là nhiều điểm có thể xảy ra lỗi hơn, không có lợi nhuận thực sự có lợi, nếu giá chiết khấu sai, nhóm kiểm tra vẫn sẽ tìm ra vấn đề, làm thế nào đơn vị kiểm tra đã cứu được bất kỳ công việc nào?

Kiểm thử đơn vị không thực sự phải tiết kiệm công việc, mà nó phải giúp bạn tìm và ngăn chặn lỗi. Đó là công việc nhiều hơn , nhưng đó là loại công việc phù hợp. Nó đang suy nghĩ về mã của bạn ở mức độ chi tiết thấp nhất và viết các trường hợp thử nghiệm chứng minh rằng nó hoạt động trong các điều kiện mong đợi , cho một tập hợp đầu vào nhất định. Nó cách ly các biến để bạn có thể tiết kiệm thời gian bằng cách tìm đúng chỗ khi lỗi xuất hiện. Đó là lưu bộ thử nghiệm đó để bạn có thể sử dụng chúng lặp đi lặp lại khi bạn phải thực hiện thay đổi.

Cá nhân tôi nghĩ rằng hầu hết các phương pháp không có nhiều bước được loại bỏ khỏi kỹ thuật phần mềm đình đám hàng hóa , bao gồm TDD, nhưng bạn không cần phải tuân thủ TDD nghiêm ngặt để thu được lợi ích của kiểm thử đơn vị. Giữ lại những phần tốt và loại bỏ những phần mang lại ít lợi ích.

Cuối cùng, câu trả lời cho câu hỏi tiêu chuẩn của bạn " Làm thế nào để bạn kiểm tra đơn vị một bài kiểm tra đơn vị? " Là bạn không cần phải làm. Mỗi bài kiểm tra đơn vị phải đơn giản. Gọi một phương thức có đầu vào cụ thể và so sánh với đầu ra mong đợi của nó. Nếu đặc điểm kỹ thuật cho một phương pháp thay đổi thì bạn có thể mong đợi rằng một số bài kiểm tra đơn vị cho phương pháp đó cũng sẽ cần thay đổi. Đó là một trong những lý do mà bạn thực hiện kiểm thử đơn vị ở mức độ chi tiết thấp như vậy, vì vậy chỉ một số kiểm thử đơn vị phải thay đổi. Nếu bạn thấy rằng các thử nghiệm cho nhiều phương pháp khác nhau đang thay đổi cho một thay đổi trong một yêu cầu, thì bạn có thể không thử nghiệm ở mức độ chi tiết đủ tốt.


"Gọi một phương thức với một đầu vào cụ thể và so sánh nó với đầu ra mong đợi của nó." nhưng điều gì sẽ xảy ra nếu đầu ra là một kiểu phức tạp ... như một tài liệu XML. Bạn không thể chỉ "==", bạn sẽ phải viết mã so sánh cụ thể, và sau đó có thể phương pháp so sánh của bạn có thể bị lỗi ??
andy,

@andy: Bạn phải thử nghiệm riêng phương pháp so sánh của mình. Khi bạn đã kiểm tra kỹ lưỡng nó, bạn có thể tin tưởng vào nó hoạt động trong các thử nghiệm khác.
Bill the Lizard,

tuyệt, cảm ơn Bill. Tôi đã bắt đầu làm việc tại một nơi mới và đây là lần đầu tiên tôi làm việc với Unit Testing. Tôi nghĩ về nguyên tắc nó hoạt động và chúng tôi đang sử dụng Cruise Control nơi nó thực sự hữu ích, nhưng những bộ thử nghiệm lớn dường như chịu chung số phận với mã kế thừa ... Tôi chỉ không chắc về nó ....
andy

11

Các bài kiểm tra đơn vị ở đó để các đơn vị (phương pháp) của bạn thực hiện những gì bạn mong đợi. Viết bài kiểm tra trước tiên buộc bạn phải suy nghĩ về những gì bạn mong đợi trước khi viết mã. Suy nghĩ trước khi làm luôn là một ý kiến ​​hay.

Các bài kiểm tra đơn vị phải phản ánh các quy tắc kinh doanh. Đúng là có thể có lỗi trong mã, nhưng việc viết bài kiểm tra trước tiên cho phép bạn viết nó theo quan điểm của quy tắc kinh doanh trước khi bất kỳ mã nào được viết. Tôi nghĩ rằng việc viết bài kiểm tra sau đó có nhiều khả năng dẫn đến lỗi như bạn mô tả vì bạn biết cách mã triển khai nó và bị cám dỗ chỉ để đảm bảo rằng việc triển khai là đúng - chứ không phải mục đích là đúng.

Ngoài ra, các bài kiểm tra đơn vị chỉ là một hình thức - và thấp nhất - trong số các bài kiểm tra mà bạn nên viết. Các bài kiểm tra tích hợp và các bài kiểm tra chấp nhận cũng nên được viết bởi khách hàng, nếu có thể, để đảm bảo rằng hệ thống hoạt động theo cách mà nó mong đợi. Nếu bạn tìm thấy lỗi trong quá trình kiểm tra này, hãy quay lại và viết các bài kiểm tra đơn vị (không thành công) để kiểm tra sự thay đổi trong chức năng để làm cho nó hoạt động chính xác, sau đó thay đổi mã của bạn để kiểm tra vượt qua. Bây giờ bạn có các bài kiểm tra hồi quy để nắm bắt các bản sửa lỗi của bạn.

[BIÊN TẬP]

Một điều khác mà tôi đã tìm thấy khi làm TDD. Nó gần như buộc phải thiết kế tốt theo mặc định. Điều này là do các thiết kế có tính kết hợp cao gần như không thể kiểm tra đơn vị một cách riêng lẻ. Không mất nhiều thời gian khi sử dụng TDD để nhận ra rằng việc sử dụng các giao diện, đảo ngược điều khiển và chèn phụ thuộc - tất cả các mẫu sẽ cải thiện thiết kế của bạn và giảm sự ghép nối - thực sự quan trọng đối với mã có thể kiểm tra.


Có lẽ đây là vấn đề của tôi nằm ở đâu. Tôi có thể hình dung thuật toán cho một quy tắc kinh doanh dễ dàng hơn tôi có thể hình dung kết quả, vì vậy tôi không gặp vấn đề gì khi triển khai chính mã, nhưng xem việc chế nhạo quy tắc là thừa. Có lẽ đó chỉ là cách tôi nghĩ.
FlySwat 28/10/08

Đó chính xác là những gì bạn làm trong bài kiểm tra đơn vị. Chia nhỏ thuật toán đó thành nhiều phần và kiểm tra từng phần. Thông thường, tôi thấy rằng mã của tôi tự viết vì tôi đã viết kỳ vọng trong bài kiểm tra đơn vị của mình.
tvanfosson

Mock là một thuật ngữ quá tải trong không gian thử nghiệm. Bạn không chế nhạo những gì bạn đang cố gắng kiểm tra, bạn chế nhạo những gì bạn không cố gắng kiểm tra ... Khi bạn viết bài kiểm tra cho quy tắc kinh doanh của mình, bạn tạo ra mã gọi nó - nó không chế giễu nó chút nào .
cwash

@cwash - Tôi không chắc cách nhận xét của bạn áp dụng cho câu trả lời của tôi. Tôi không đề cập đến việc chế giễu ... và tôi đồng ý với nhận xét của bạn.
tvanfosson

@tvanfosson - nhận xét cuối cùng của tôi là phản hồi cho @FlySwat "... chế nhạo quy tắc là thừa." Xin lỗi, tôi quên chỉ định.
cwash

10

Làm thế nào để kiểm tra một bài kiểm tra ? Kiểm tra đột biến là một kỹ thuật có giá trị mà cá nhân tôi đã sử dụng cho hiệu quả tốt một cách đáng ngạc nhiên. Đọc bài viết được liên kết để biết thêm chi tiết và liên kết đến nhiều tài liệu tham khảo học thuật hơn, nhưng nói chung nó "kiểm tra các bài kiểm tra của bạn" bằng cách sửa đổi mã nguồn của bạn (ví dụ: thay đổi "x + = 1" thành "x - = 1") và sau đó chạy lại các thử nghiệm của bạn, đảm bảo rằng ít nhất một thử nghiệm không thành công. Bất kỳ đột biến nào không gây ra lỗi thử nghiệm đều được gắn cờ để điều tra sau.

Bạn sẽ ngạc nhiên về cách bạn có thể có phạm vi phủ sóng 100% đường dây và chi nhánh với một bộ thử nghiệm trông toàn diện, nhưng về cơ bản bạn có thể thay đổi hoặc thậm chí nhận xét một dòng trong nguồn của mình mà không có bất kỳ thử nghiệm nào phàn nàn. Thường thì điều này xuất phát từ việc không thử nghiệm với các đầu vào phù hợp để bao gồm tất cả các trường hợp ranh giới, đôi khi nó tinh tế hơn, nhưng trong mọi trường hợp, tôi rất ấn tượng với mức độ phát ra từ nó.


1
+1 khái niệm thú vị mà tôi chưa nghe nói đến
Wim Coenen

9

Khi áp dụng Phát triển theo hướng kiểm tra (TDD), người ta bắt đầu bằng một bài kiểm tra không đạt . Bước này, có vẻ không cần thiết, thực sự là ở đây để xác minh bài kiểm tra đơn vị đang kiểm tra điều gì đó. Thật vậy, nếu bài kiểm tra không bao giờ thất bại, nó không mang lại giá trị gì và tệ hơn, dẫn đến sự tự tin sai lầm vì bạn sẽ dựa vào một kết quả dương tính mà không chứng minh được điều gì.

Khi tuân thủ nghiêm ngặt quy trình này, tất cả '' đơn vị '' đều được bảo vệ bởi mạng lưới an toàn mà các thử nghiệm đơn vị đang thực hiện, ngay cả những điều trần tục nhất.

Assert.IsEqual(p.DiscountPrice,90);

Không có lý do gì mà bài kiểm tra lại phát triển theo hướng đó - hoặc tôi thiếu điều gì đó trong suy luận của bạn. Khi giá là 100 và chiết khấu 20, giá chiết khấu là 80. Điều này giống như một bất biến.

Bây giờ, hãy tưởng tượng phần mềm của bạn cần hỗ trợ một loại chiết khấu khác dựa trên tỷ lệ phần trăm, có lẽ tùy thuộc vào khối lượng đã mua, phương thức Product :: ReducePrice () của bạn có thể trở nên phức tạp hơn. Và có thể việc đưa ra những thay đổi đó phá vỡ quy tắc chiết khấu đơn giản mà chúng tôi đã có ban đầu. Sau đó, bạn sẽ thấy giá trị của kiểm tra này sẽ phát hiện ra hồi quy ngay lập tức.


Red - Green - Refactor - đây là để ghi nhớ bản chất của quá trình TDD.

Màu đỏ đề cập đến thanh màu đỏ JUnit khi kiểm tra không thành công.

Màu xanh lá cây là màu của thanh tiến trình JUnit khi tất cả các bài kiểm tra vượt qua.

Refactor trong điều kiện màu xanh lá cây: loại bỏ mọi trùng lặp, cải thiện khả năng đọc.


Bây giờ để giải quyết quan điểm của bạn về "3-4 lớp phía trên mã", điều này đúng trong quy trình truyền thống (giống như thác nước), không phải khi quy trình phát triển nhanh. Và nhanh nhẹn là thế giới mà TDD hình thành; TDD là nền tảng của Lập trình eXtreme .

Agile là về giao tiếp trực tiếp chứ không phải là tài liệu yêu cầu ném qua tường.


8

Trong khi, tất cả tôi đều dành cho thử nghiệm đơn vị, đôi khi tôi tự hỏi liệu hình thức phát triển thử nghiệm đầu tiên này có thực sự mang lại lợi ích hay không ...

Các bài kiểm tra nhỏ, tầm thường như thế này có thể là "con chim hoàng yến trong mỏ than" cho cơ sở mã của bạn, cảnh báo nguy hiểm trước khi quá muộn. Các thử nghiệm nhỏ rất hữu ích để duy trì vì chúng giúp bạn thực hiện đúng các tương tác.

Ví dụ: hãy nghĩ về một thử nghiệm nhỏ được thực hiện để thăm dò cách sử dụng API mà bạn không quen thuộc. Nếu kiểm tra đó có bất kỳ liên quan nào đến những gì bạn đang làm trong mã sử dụng API "cho thực tế", thì việc duy trì kiểm tra đó sẽ rất hữu ích. Khi API phát hành phiên bản mới và bạn cần nâng cấp. Bây giờ bạn có các giả định về cách bạn mong đợi API hoạt động được ghi lại ở định dạng thực thi mà bạn có thể sử dụng để bắt các hồi quy.

... [I] na là quy trình thực, bạn có 3-4 lớp phía trên mã của mình (Yêu cầu kinh doanh, Tài liệu yêu cầu, Tài liệu kiến ​​trúc), trong đó quy tắc kinh doanh được xác định thực tế (Giá chiết khấu là Giá - Chiết khấu) có thể được xác định sai. Nếu đó là tình huống, bài kiểm tra đơn vị của bạn không có ý nghĩa gì đối với bạn.

Nếu bạn đã viết mã trong nhiều năm mà không viết các bài kiểm tra, bạn có thể không thấy ngay rằng có bất kỳ giá trị nào. Nhưng nếu bạn có suy nghĩ rằng cách tốt nhất để làm việc là "phát hành sớm, phát hành thường xuyên" hoặc "nhanh nhẹn" trong đó bạn muốn khả năng triển khai nhanh / liên tục, thì thử nghiệm của bạn chắc chắn có ý nghĩa. Cách duy nhất để làm điều này là hợp pháp hóa mọi thay đổi bạn thực hiện đối với mã bằng một bài kiểm tra. Bất kể thử nghiệm nhỏ đến mức nào, một khi bạn có bộ thử nghiệm xanh, về mặt lý thuyết, bạn có thể triển khai. Xem thêm "sản xuất liên tục" và "phiên bản beta vĩnh viễn."

Bạn cũng không cần phải "kiểm tra đầu tiên" để có được tư duy này, nhưng đó nói chung là cách hiệu quả nhất để đạt được điều đó. Khi bạn thực hiện TDD, bạn tự nhốt mình vào chu kỳ Tái cấu trúc màu xanh đỏ nhỏ từ hai đến ba phút. Chẳng có lúc nào bạn không thể dừng lại và rời đi và có một mớ hỗn độn hoàn chỉnh trên tay mà bạn sẽ mất một giờ để gỡ lỗi và lắp lại.

Ngoài ra, bài kiểm tra đơn vị của bạn là một điểm thất bại khác ...

Một bài kiểm tra thành công là một bài kiểm tra chứng tỏ sự thất bại trong hệ thống. Một bài kiểm tra không đạt sẽ cảnh báo bạn về một lỗi trong logic của bài kiểm tra hoặc trong logic của hệ thống của bạn. Mục tiêu của các bài kiểm tra là phá vỡ mã của bạn hoặc chứng minh một kịch bản hoạt động.

Nếu bạn đang viết các bài kiểm tra sau khi viết mã, bạn sẽ có nguy cơ viết một bài kiểm tra "xấu" bởi vì để thấy rằng bài kiểm tra của bạn thực sự hoạt động, bạn cần phải xem nó bị hỏng và hoạt động. Khi bạn đang viết các bài kiểm tra sau mã, điều này có nghĩa là bạn phải "giăng bẫy" và đưa một lỗi vào mã để kiểm tra không thành công. Hầu hết các nhà phát triển không chỉ không thoải mái về điều này mà còn cho rằng đó là một sự lãng phí thời gian.

Chúng ta đạt được gì ở đây?

Chắc chắn có một lợi ích khi làm mọi thứ theo cách này. Michael Feathers định nghĩa "mã kế thừa" là "mã chưa được kiểm tra". Khi bạn thực hiện phương pháp này, bạn hợp pháp hóa mọi thay đổi bạn thực hiện đối với cơ sở mã của mình. Nó khắt khe hơn việc không sử dụng các bài kiểm tra, nhưng khi nói đến việc duy trì một cơ sở mã lớn, nó sẽ tự trả tiền.

Nói về Feathers, có hai tài nguyên tuyệt vời mà bạn nên kiểm tra về vấn đề này:

Cả hai điều này đều giải thích cách thực hiện các loại thực hành và kỷ luật này vào các dự án không phải là "Greenfield". Họ cung cấp các kỹ thuật để viết các bài kiểm tra xung quanh các thành phần được kết hợp chặt chẽ, phụ thuộc có dây cứng và những thứ mà bạn không nhất thiết phải kiểm soát. Đó là tất cả về việc tìm kiếm "đường nối" và thử nghiệm xung quanh chúng.

[Tôi] nếu giá chiết khấu là sai, nhóm thử nghiệm vẫn sẽ tìm ra vấn đề, làm thế nào mà thử nghiệm đơn vị đã tiết kiệm được bất kỳ công việc nào?

Những thói quen như thế này giống như một khoản đầu tư. Lợi nhuận không ngay lập tức; chúng tích tụ theo thời gian. Giải pháp thay thế cho việc không thử nghiệm về cơ bản là gánh nợ không thể bắt các hồi quy, giới thiệu mã mà không sợ lỗi tích hợp hoặc quyết định thiết kế. Cái hay là bạn hợp pháp hóa mọi thay đổi được đưa vào codebase của bạn.

Tôi còn thiếu gì ở đây? Xin hãy dạy tôi yêu TDD, vì tôi đang rất khó chấp nhận nó là hữu ích cho đến nay. Tôi cũng muốn, vì tôi muốn tiếp tục tiến bộ, nhưng nó không có ý nghĩa gì đối với tôi.

Tôi xem đó như một trách nhiệm nghề nghiệp. Đó là một lý tưởng để phấn đấu. Nhưng nó rất khó để làm theo và tẻ nhạt. Nếu bạn quan tâm đến nó và cảm thấy bạn không nên tạo ra mã không được kiểm tra, bạn sẽ có thể tìm thấy sức mạnh ý chí để học các thói quen kiểm tra tốt. Một điều mà tôi làm rất nhiều bây giờ (cũng như những người khác) là tự mình đặt hộp thời gian một giờ để viết mã mà không cần bất kỳ bài kiểm tra nào, sau đó có kỷ luật để vứt bỏ nó. Điều này có vẻ lãng phí nhưng thực sự không phải vậy. Nó không giống như việc tập thể dục tiêu tốn tài liệu vật chất của công ty. Nó giúp tôi hiểu được vấn đề và cách viết mã theo cách có chất lượng cao hơn và có thể kiểm tra được.

Lời khuyên của tôi cuối cùng sẽ là nếu bạn thực sự không có mong muốn trở thành người giỏi nó, thì đừng làm điều đó. Các bài kiểm tra kém không được duy trì, không hoạt động tốt, v.v. có thể tồi tệ hơn là không có bất kỳ bài kiểm tra nào. Thật khó để tự học và có thể bạn sẽ không yêu thích nó, nhưng bạn sẽ không thể học được nếu bạn không có mong muốn thực hiện nó hoặc không thể thấy đủ giá trị của nó để đảm bảo đầu tư thời gian.

Một số người vẫn đề cập rằng thử nghiệm giúp thực thi thông số kỹ thuật. Theo kinh nghiệm của tôi, thông số kỹ thuật cũng bị sai, thường xuyên hơn là không ...

Bàn phím của một nhà phát triển là nơi mà cao su gặp mặt đường. Nếu thông số kỹ thuật sai và bạn không giơ cờ về nó, thì rất có thể bạn sẽ bị đổ lỗi cho nó. Hoặc ít nhất mã của bạn sẽ. Kỷ luật và sự nghiêm ngặt liên quan đến thử nghiệm rất khó tuân thủ. Nó không dễ dàng chút nào. Nó cần thực hành, rất nhiều học hỏi và rất nhiều sai lầm. Nhưng cuối cùng nó cũng được đền đáp. Trong một dự án có nhịp độ nhanh, thay đổi nhanh chóng, đó là cách duy nhất để bạn có thể ngủ vào ban đêm, bất kể nó có làm bạn chậm lại hay không.

Một điều khác cần suy nghĩ ở đây là các kỹ thuật về cơ bản giống như kiểm thử đã được chứng minh là hoạt động trong quá khứ: "phòng sạch" và "thiết kế theo hợp đồng" đều có xu hướng tạo ra các loại cấu trúc "meta" -code giống nhau. kiểm tra thực hiện và thực thi chúng ở các điểm khác nhau. Không có kỹ thuật nào trong số này là những viên đạn bạc và sự khắt khe cuối cùng sẽ khiến bạn phải trả giá trong phạm vi các tính năng mà bạn có thể cung cấp về thời gian đưa ra thị trường. Nhưng đó không phải là những gì nó về. Đó là về khả năng duy trì những gì bạn cung cấp. Và điều đó rất quan trọng đối với hầu hết các dự án.


7

Kiểm tra đơn vị hoạt động rất giống với việc ghi sổ kép. Bạn nêu cùng một điều (quy tắc kinh doanh) theo hai cách khá khác nhau (như các quy tắc được lập trình trong mã sản xuất của bạn và như các ví dụ đơn giản, đại diện trong các thử nghiệm của bạn). Rất ít khả năng bạn mắc cùng một sai lầm ở cả hai, vì vậy nếu cả hai đều đồng ý với nhau, thì không chắc là bạn đã sai.

Làm thế nào để thử nghiệm trở nên xứng đáng với nỗ lực? Theo kinh nghiệm của tôi về ít nhất bốn cách, ít nhất là khi thực hiện phát triển theo hướng thử nghiệm:

  • nó giúp bạn đưa ra một thiết kế tách rời tốt. Bạn chỉ có thể mã kiểm tra đơn vị được tách rời tốt;
  • nó giúp bạn xác định khi nào bạn hoàn thành. Việc phải chỉ định hành vi cần thiết trong các thử nghiệm giúp không xây dựng chức năng mà bạn thực sự không cần và xác định khi nào chức năng hoàn thành;
  • nó cung cấp cho bạn một mạng lưới an toàn để tái cấu trúc, làm cho mã dễ dàng thay đổi hơn nhiều; và
  • nó giúp bạn tiết kiệm rất nhiều thời gian gỡ lỗi, điều này gây tốn kém kinh khủng (tôi đã nghe ước tính rằng theo truyền thống, các nhà phát triển dành tới 80% thời gian để gỡ lỗi).

5

Hầu hết các bài kiểm tra đơn vị, bài kiểm tra giả định. Trong trường hợp này, giá chiết khấu phải là giá trừ đi khoản chiết khấu. Nếu giả định của bạn là sai, tôi cá rằng mã của bạn cũng sai. Và nếu bạn mắc một lỗi ngớ ngẩn, bài kiểm tra sẽ thất bại và bạn sẽ sửa lại.

Nếu các quy tắc thay đổi, bài kiểm tra sẽ không thành công và đó là một điều tốt. Vì vậy, bạn phải thay đổi bài kiểm tra trong trường hợp này.

Theo nguyên tắc chung, nếu thử nghiệm không thành công ngay lập tức (và bạn không sử dụng thiết kế thử nghiệm đầu tiên), thì thử nghiệm hoặc mã sai (hoặc cả hai nếu bạn đang có một ngày tồi tệ). Bạn sử dụng cách hiểu thông thường (và theo các thông số kỹ thuật) để sửa mã vi phạm và chạy lại kiểm tra.

Giống như Jason đã nói, kiểm tra là bảo mật. Và vâng, đôi khi họ giới thiệu công việc thêm vì các bài kiểm tra bị lỗi. Nhưng hầu hết thời gian họ là những người tiết kiệm thời gian rất lớn. (Và bạn có cơ hội hoàn hảo để trừng phạt anh chàng làm hỏng bài kiểm tra (chúng ta đang nói gà cao su)).


4

Kiểm tra mọi thứ bạn có thể. Ngay cả những sai lầm nhỏ nhặt, chẳng hạn như quên chuyển đổi mét sang feet có thể có tác dụng phụ rất đắt. Viết bài kiểm tra, viết mã để nó kiểm tra, vượt qua, tiếp tục. Biết đâu một thời điểm nào đó trong tương lai sẽ có người đổi mã giảm giá. Một bài kiểm tra có thể phát hiện ra vấn đề.


Điều đó không giải quyết bất kỳ suy nghĩ nào của tôi. Tôi hiểu câu thần chú cơ bản của TDD ... Tôi không thấy lợi ích.
FlySwat 28/10/08

4

Tôi thấy các bài kiểm tra đơn vị và mã sản xuất có mối quan hệ cộng sinh. Nói một cách đơn giản: cái này kiểm tra cái kia. Và cả hai đều kiểm tra nhà phát triển.


3

Hãy nhớ rằng chi phí sửa chữa các khuyết tật tăng lên (theo cấp số nhân) khi các khuyết tật tồn tại trong suốt chu kỳ phát triển. Có, nhóm kiểm tra có thể bắt được lỗi, nhưng (thường) sẽ mất nhiều công việc hơn để cô lập và sửa lỗi từ thời điểm đó so với nếu một bài kiểm tra đơn vị không thành công và sẽ dễ dàng hơn để đưa ra các lỗi khác trong khi sửa chữa nó nếu bạn không có các bài kiểm tra đơn vị để chạy.

Điều đó thường dễ thấy hơn với một cái gì đó hơn là một ví dụ tầm thường ... và với những ví dụ tầm thường, tốt, nếu bạn bằng cách nào đó làm sai lệch bài kiểm tra đơn vị, người xem xét nó sẽ bắt lỗi trong bài kiểm tra hoặc lỗi trong mã, hoặc cả hai. (Chúng đang được xem xét, đúng không?) Như tvanfosson đã chỉ ra , kiểm thử đơn vị chỉ là một phần của kế hoạch SQA.

Theo một nghĩa nào đó, các bài kiểm tra đơn vị là bảo hiểm. Họ không đảm bảo rằng bạn sẽ phát hiện ra mọi khiếm khuyết và đôi khi có vẻ như bạn đang dành rất nhiều nguồn lực cho chúng, nhưng khi chúng phát hiện ra những khiếm khuyết mà bạn có thể sửa chữa, bạn sẽ chi tiêu ít hơn rất nhiều so với trường hợp bạn không có thử nghiệm nào cả và phải sửa tất cả các lỗi ở phần hạ lưu.


3

Tôi hiểu quan điểm của bạn, nhưng rõ ràng nó đã bị phóng đại quá mức.

Lập luận của bạn về cơ bản là: Thử nghiệm giới thiệu sự thất bại. Do đó các bài kiểm tra rất tệ / lãng phí thời gian.

Mặc dù điều đó có thể đúng trong một số trường hợp, nhưng nó hầu như không phải là đa số.

TDD giả định: Nhiều thử nghiệm hơn = Ít thất bại hơn.

Các bài kiểm tra có nhiều khả năng bắt được điểm không thành công hơn là giới thiệu chúng.


1

Tự động hóa nhiều hơn có thể giúp ở đây! Có, viết bài kiểm tra đơn vị có thể rất nhiều công việc, vì vậy hãy sử dụng một số công cụ để giúp bạn. Hãy xem một cái gì đó như Pex, của Microsoft, nếu bạn đang sử dụng .Net Nó sẽ tự động tạo các bộ kiểm tra đơn vị cho bạn bằng cách kiểm tra mã của bạn. Nó sẽ đưa ra các bài kiểm tra cung cấp độ phủ tốt, cố gắng bao phủ tất cả các đường dẫn thông qua mã của bạn.

Tất nhiên, chỉ bằng cách nhìn vào mã của bạn, nó không thể biết bạn thực sự đang cố gắng làm gì, vì vậy nó không biết nó có chính xác hay không. Tuy nhiên, nó sẽ tạo ra các trường hợp kiểm tra thú vị cho bạn và sau đó bạn có thể kiểm tra chúng và xem liệu nó có hoạt động như bạn mong đợi hay không.

Sau đó, nếu bạn đi xa hơn và viết các bài kiểm tra đơn vị được tham số hóa (thực sự bạn có thể coi đây là các hợp đồng), nó sẽ tạo ra các trường hợp thử nghiệm cụ thể từ những trường hợp này và lần này nó có thể biết nếu có gì đó sai, bởi vì các xác nhận của bạn trong các thử nghiệm sẽ thất bại.


1

Tôi đã nghĩ một chút về một cách hay để trả lời câu hỏi này và muốn rút ra một phương pháp song song với phương pháp khoa học. IMO, bạn có thể diễn đạt lại câu hỏi này, "Bạn thử nghiệm một thử nghiệm như thế nào?"

Các thí nghiệm xác minh các giả định thực nghiệm (giả thuyết) về vũ trụ vật chất. Các bài kiểm tra đơn vị sẽ kiểm tra các giả định về trạng thái hoặc hành vi của mã mà chúng gọi. Chúng ta có thể nói về tính hợp lệ của một thí nghiệm, nhưng đó là bởi vì chúng ta biết, thông qua nhiều thí nghiệm khác, rằng có điều gì đó không phù hợp. Nó không có cả giá trị hội tụbằng chứng thực nghiệm . Chúng tôi không thiết kế một thử nghiệm mới để kiểm tra hoặc xác minh tính hợp lệ của một thử nghiệm , nhưng chúng tôi có thể thiết kế một thử nghiệm hoàn toàn mới .

Vì vậy, giống như các thí nghiệm , chúng tôi không mô tả tính hợp lệ của một bài kiểm tra đơn vị dựa trên việc nó có vượt qua bài kiểm tra đơn vị hay không. Cùng với các bài kiểm tra đơn vị khác, nó mô tả các giả định mà chúng tôi đưa ra về hệ thống mà nó đang kiểm tra. Ngoài ra, giống như các thử nghiệm, chúng tôi cố gắng loại bỏ sự phức tạp nhiều nhất có thể khỏi những gì chúng tôi đang thử nghiệm. "Càng đơn giản càng tốt, nhưng không đơn giản hơn."

Không giống như các thử nghiệm , chúng tôi có một mẹo nhỏ để xác minh rằng các thử nghiệm của chúng tôi là hợp lệ thay vì chỉ hợp lệ hội tụ. Chúng ta có thể khéo léo đưa ra một lỗi mà chúng ta biết là cần được kiểm tra bắt gặp và xem liệu bài kiểm tra có thực sự thất bại hay không. (Giá như chúng ta có thể làm điều đó trong thế giới thực, chúng ta sẽ ít phụ thuộc hơn vào điều hợp lệ hội tụ này!) Một cách hiệu quả hơn để làm điều này là xem thử nghiệm của bạn không thành công trước khi thực hiện (bước màu đỏ trong Red, Green, Refactor ).


1

Bạn cần sử dụng mô hình chính xác khi viết bài kiểm tra.

  1. Bắt đầu bằng cách viết các bài kiểm tra của bạn trước.
  2. Hãy chắc chắn rằng họ không bắt đầu với.
  3. Làm cho họ vượt qua.
  4. Xem lại mã trước khi bạn kiểm tra mã của mình (đảm bảo rằng các bài kiểm tra đã được xem xét.)

Bạn không thể luôn chắc chắn nhưng chúng cải thiện các bài kiểm tra tổng thể.


0

Ngay cả khi bạn không kiểm tra mã của mình, nó chắc chắn sẽ được kiểm tra trong quá trình sản xuất bởi người dùng của bạn. Người dùng rất sáng tạo trong việc cố gắng sửa lỗi phần mềm của bạn và tìm ra những lỗi không nghiêm trọng.

Sửa lỗi trong quá trình sản xuất tốn kém hơn nhiều so với việc giải quyết các vấn đề trong giai đoạn phát triển. Như một tác dụng phụ, bạn sẽ mất thu nhập vì lượng khách hàng đổ ra ngoài. Bạn có thể tính đến 11 khách hàng bị mất hoặc không có được cho 1 khách hàng tức giận.

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.