2008-09-15 49 views
118

Sử dụng C#, tôi cần một lớp được gọi là User rằng có một tên người dùng, mật khẩu, cờ hoạt động, tên, họ, tên đầy đủ, vvLàm thế nào để bạn biết những gì để kiểm tra khi viết bài kiểm tra đơn vị?

Nên có phương pháp để xác thựctiết kiệm người dùng . Tôi chỉ viết một bài kiểm tra cho các phương pháp? Và tôi thậm chí cần phải lo lắng về việc kiểm tra các thuộc tính kể từ khi chúng được .Net's getter và setters?

Trả lời

123

Nhiều câu trả lời tuyệt vời để này cũng nằm trong câu hỏi của tôi: "Beginning TDD - Challenges? Solutions? Recommendations?"

Có thể tôi cũng khuyên bạn nên tham gia một cái nhìn của tôi blog post (được một phần lấy cảm hứng từ câu hỏi của tôi), tôi đã có một số thông tin phản hồi tốt về điều đó . Cụ thể:

Tôi không biết bắt đầu từ đâu?

  • Bắt đầu lại. Chỉ nghĩ đến việc viết bài kiểm tra khi bạn đang viết mã mới . Điều này có thể hoạt động lại với mã số cũ hoặc một tính năng hoàn toàn mới.
  • Bắt đầu đơn giản. Đừng bỏ chạy và cố gắng làm cho đầu của bạn trở thành một khuôn khổ thử nghiệm cũng như đang được TDD-esque thực hiện. Debug.Assert hoạt động tốt. Sử dụng nó làm điểm xuất phát. Nó không gây rối với dự án của bạn hoặc tạo phụ thuộc .
  • Bắt đầu tích cực. Bạn đang cố gắng cải thiện thủ công của mình, cảm thấy hài lòng về số điện thoại . Tôi đã thấy nhiều nhà phát triển ngoài kia vui vẻ trì trệ và không thử những điều mới mẻ để tự mình tốt hơn . Bạn đang làm đúng điều , hãy nhớ điều này và điều này sẽ giúp ngăn bạn từ bỏ.
  • Bắt đầu sẵn sàng cho thử thách. Thật khó để bắt đầu tham gia thử nghiệm . Mong đợi một thách thức, nhưng nhớ - những thách thức có thể được khắc phục.

Chỉ thử nghiệm cho những gì bạn mong đợi

Tôi đã có vấn đề thực sự khi tôi lần đầu tiên bắt đầu bởi vì tôi đã không ngừng ngồi có cố gắng tìm ra mọi vấn đề thể có thể xảy ra và sau đó cố gắng để kiểm tra cho nó và sửa chữa. Đây là cách nhanh chóng để gây đau đầu. Thử nghiệm phải là quy trình YAGNI thực sự. Nếu bạn biết có sự cố , hãy viết bài kiểm tra cho nó. Nếu không, đừng bận tâm.

Chỉ thử nghiệm Một Thing

Mỗi bộ test chỉ nên kiểm tra một điều. Nếu bạn từng thấy mình đặt “và” trong tên trường hợp thử nghiệm, bạn đang làm điều gì đó sai.

Tôi hy vọng điều này có nghĩa là chúng ta có thể di chuyển trên từ "getter và setter" :)

+2

"Nếu bạn biết có vấn đề, hãy viết một bài kiểm tra cho nó. Nếu không, đừng bận tâm." Tôi sẽ không đồng ý với cách này được diễn đạt.Tôi đã được ấn tượng rằng các bài kiểm tra đơn vị nên bao gồm tất cả các đường dẫn thực hiện có thể. –

+2

Trong khi một số người có thể ủng hộ những điều như vậy, cá nhân tôi thì không. 90% cơn đau đầu của tôi đến từ việc chỉ đơn giản là cố gắng làm "mọi thứ". Tôi nói thử nghiệm cho những gì bạn mong đợi xảy ra (vì vậy bạn biết bạn đang nhận được các giá trị đúng trở lại) nhưng không cố gắng và con số nó tất cả ra ngoài. YAGNI. –

+3

Tôi cũng ủng hộ cách tiếp cận "kiểm tra lỗi của bạn". Nếu tất cả chúng ta đều có thời gian và kiên nhẫn vô hạn, chúng tôi sẽ kiểm tra mọi con đường thi hành có thể. Nhưng chúng tôi không, vì vậy bạn phải dành nhiều nỗ lực của bạn, nơi nó sẽ có hiệu quả lớn nhất. – Schwern

-3

Tôi không thể nói C# cụ thể, nhưng khi tôi viết bài kiểm tra đơn vị, tôi kiểm tra MỌI đầu vào, ngay cả những người dùng không làm, theo cách đó tôi biết cách ngăn chặn những sai lầm của riêng mình.

9

Quy tắc là bạn phải kiểm tra từng đoạn logic bạn viết. Nếu bạn thực hiện một số chức năng cụ thể trong getters và setters tôi nghĩ rằng họ là giá trị thử nghiệm. Nếu họ chỉ gán giá trị cho một số trường riêng tư, đừng bận tâm.

1

Khi tôi hiểu các bài kiểm tra đơn vị trong bối cảnh phát triển nhanh, Mike, có, bạn cần phải kiểm tra các getters và setters (giả sử chúng được hiển thị công khai). Toàn bộ khái niệm kiểm tra đơn vị là để kiểm tra đơn vị phần mềm, là một lớp trong trường hợp này, như là một black box. Vì các getters và setters có thể nhìn thấy bên ngoài, bạn cần kiểm tra chúng cùng với Authenticate và Save.

2

Không đau khi viết các bài kiểm tra đơn vị cho getters và setters của bạn. Ngay bây giờ, họ có thể chỉ làm lĩnh vực get/bộ dưới mui xe, nhưng trong tương lai bạn có thể có logic xác nhận, hoặc phụ thuộc liên thuộc tính cần phải được kiểm tra. Nó dễ dàng hơn để viết nó ngay bây giờ trong khi bạn đang suy nghĩ về nó sau đó nhớ để trang bị thêm nó nếu thời gian đó đến.

+0

tốt, nếu getters/setters của bạn cần kiểm tra đơn vị, phải có một số logic liên kết với chúng, nghĩa là logic phải được viết bên trong chúng, nếu chúng không có bất kỳ logic nào thì không cần phải viết đơn vị kiểm tra nào. –

+2

Quan điểm của ông là logic có thể được thêm vào sau này. – LegendLength

1

Nếu phương pháp Xác thực và Lưu sử dụng thuộc tính, thì các thử nghiệm của bạn sẽ gián tiếp chạm vào các thuộc tính. Miễn là các thuộc tính chỉ cung cấp quyền truy cập vào dữ liệu, thì việc kiểm tra rõ ràng không cần thiết (trừ khi bạn đang sử dụng mức độ phù hợp 100%).

59

Kiểm tra mã của bạn, không phải ngôn ngữ.

Một thử nghiệm đơn vị như:

Integer i = new Integer(7); 
assert (i.instanceOf(integer)); 

chỉ hữu ích nếu bạn đang viết một trình biên dịch và có một khác không cơ hội mà phương pháp instanceof của bạn không hoạt động.

Đừng kiểm tra nội dung mà bạn có thể dựa vào ngôn ngữ để thực thi. Trong trường hợp của bạn, tôi sẽ tập trung vào việc xác thực và lưu các phương thức - và tôi sẽ viết các bài kiểm tra để đảm bảo rằng chúng có thể xử lý các giá trị null trong bất kỳ hoặc tất cả các trường đó một cách duyên dáng.

+0

Điểm tốt trên "Không kiểm tra khung" - Tôi cũng đã từng nhận được điều mới mẻ khi làm điều này. + 1'ed :) –

1

Tôi sẽ kiểm tra getters và setters của bạn. Tùy thuộc vào người viết mã, một số người thay đổi ý nghĩa của các phương thức getter/setter. Tôi đã nhìn thấy khởi tạo biến và xác nhận khác như một phần của phương thức getter. Để kiểm tra loại điều này, bạn muốn kiểm tra đơn vị bao gồm mã đó một cách rõ ràng.

1

Cá nhân tôi sẽ "kiểm tra mọi thứ có thể bị hỏng" và trình khởi động đơn giản (hoặc các thuộc tính tự động tốt hơn) sẽ không bị ngắt. Tôi chưa bao giờ có một tuyên bố trở lại đơn giản thất bại và không bao giờ có kiểm tra cho họ. Nếu getters có tính toán bên trong chúng hoặc một số hình thức khác của báo cáo, tôi chắc chắn sẽ thêm các xét nghiệm cho họ.

Cá nhân tôi sử dụng Moq làm khung đối tượng giả và sau đó xác minh rằng đối tượng của tôi gọi các đối tượng xung quanh theo cách cần thiết.

1

Bạn phải thực hiện mọi phương thức của lớp bằng UT và kiểm tra giá trị trả về của phương thức. Điều này bao gồm getters và setters, đặc biệt là trong trường hợp các thành viên (thuộc tính) là các lớp phức tạp, yêu cầu cấp phát bộ nhớ lớn trong quá trình khởi tạo của chúng. Gọi setter với một số chuỗi rất lớn ví dụ (hoặc một cái gì đó với các biểu tượng Hy Lạp) và kiểm tra kết quả là chính xác (không cắt ngắn, mã hóa là tốt vv)

Trong trường hợp số nguyên đơn giản cũng áp dụng - những gì sẽ xảy ra nếu bạn vượt qua dài thay vì số nguyên? Đó là lý do bạn viết UT cho :)

12

Nếu chúng thực sự tầm thường, thì đừng bận tâm kiểm tra. Ví dụ, nếu chúng được thực hiện như thế này;

public class User 
{ 
    public string Username { get; set; } 
    public string Password { get; set; } 
} 

Nếu, mặt khác, bạn đang làm điều gì đó thông minh (như mã hóa và giải mã mật khẩu trong bộ thu thập dữ liệu) sau đó kiểm tra.

1

nghiệm của một lớp nên xác minh rằng:

  1. phương pháp và tài sản trở về giá trị dự kiến ​​
  2. excepts thích hợp được ném khi một cuộc tranh cãi không hợp lệ được cung cấp
  3. Tương tác giữa các lớp và các đối tượng khác xảy ra như mong đợi khi một phương pháp nhất định được gọi là

Tất nhiên nếu getters và setters không có logic đặc biệt thì các phép thử của Authenticate andSave m ethods nên bao gồm chúng, nhưng nếu không, một thử nghiệm explict nên được viết

1

Tôi sẽ không kiểm tra cài đặt thực tế của thuộc tính. Tôi sẽ quan tâm nhiều hơn đến cách những tài sản đó được người tiêu dùng dân cư, và những gì họ cư trú với họ. Với bất kỳ thử nghiệm nào, bạn phải cân nhắc rủi ro với thời gian/chi phí thử nghiệm.

1

Bạn nên kiểm tra "mọi khối mã không tầm thường" bằng cách sử dụng các kiểm tra đơn vị càng nhiều càng tốt.

Nếu tài sản của bạn là tầm thường và không chắc ai đó sẽ giới thiệu một lỗi trong đó, thì nên an toàn để không đơn vị kiểm tra chúng.

Phương thức Authenticate() và Save() của bạn trông giống như các ứng cử viên tốt để thử nghiệm.

3

Kiểm tra mã boilerplate là một sự lãng phí thời gian, nhưng như Slavo nói, nếu bạn thêm một hiệu ứng phụ vào getters/setters của bạn, thì bạn nên viết một bài kiểm tra để đi cùng với chức năng đó.

Nếu bạn đang phát triển thử nghiệm, bạn nên viết hợp đồng (ví dụ: giao diện) trước, sau đó viết (các) bài kiểm tra để thực hiện giao diện ghi lại kết quả/hành vi mong đợi. Sau đó, tự viết các phương thức của bạn mà không cần chạm vào mã trong các bài kiểm tra đơn vị của bạn. Cuối cùng, lấy một công cụ bảo hiểm mã và đảm bảo các bài kiểm tra của bạn thực hiện tất cả các đường dẫn logic trong mã của bạn.

1

Lý tưởng nhất, bạn đã thực hiện các bài kiểm tra đơn vị của mình khi bạn đang viết lớp. Đây là cách bạn định làm điều đó khi sử dụng Phát triển thử nghiệm. Bạn thêm các bài kiểm tra khi bạn thực hiện từng điểm chức năng, đảm bảo rằng bạn cũng bao gồm các trường hợp cạnh với thử nghiệm.

Viết các bài kiểm tra sau đó sẽ đau đớn hơn nhiều, nhưng có thể thực hiện được.

Đây là những gì tôi muốn làm trong vị trí của bạn:

  1. Viết một thiết lập cơ bản của các bài kiểm tra thử nghiệm các chức năng cốt lõi.
  2. Nhận NCover và chạy thử nghiệm của bạn. Phạm vi kiểm tra của bạn có thể sẽ vào khoảng 50% vào thời điểm này.
  3. kiểm tra tiếp tục bổ sung bao phủ cạnh trường hợp của bạn cho đến khi bạn có được vùng phủ sóng khoảng 80% -90%

này sẽ cho bạn một bộ làm việc tốt đẹp của các bài kiểm tra đơn vị đó sẽ hoạt động như một bộ đệm tốt chống lại hồi quy.

Vấn đề duy nhất với cách tiếp cận này là mã phải là được thiết kế để có thể kiểm tra theo cách này. Nếu bạn đã thực hiện bất kỳ sai lầm khớp nối sớm nào, bạn sẽ không thể nhận được mức độ phù hợp cao một cách dễ dàng.

Đây là lý do tại sao việc viết các bài kiểm tra trước khi bạn viết mã thực sự quan trọng. Nó buộc bạn phải viết mã được kết hợp lỏng lẻo.

1

Không kiểm tra mã hoạt động rõ ràng (bản mẫu). Vì vậy, nếu setters và getters của bạn chỉ là "propertyvalue = value" và "return propertyvalue", nó không có ý nghĩa để kiểm tra nó.

1

Ngay cả khi nhận/đặt có thể có hậu quả lạ, tùy thuộc vào cách chúng được triển khai, vì vậy chúng phải được coi là phương pháp.

Mỗi thử nghiệm trong số này sẽ cần phải xác định bộ thông số cho thuộc tính, xác định cả thuộc tính có thể chấp nhận và không được chấp nhận để đảm bảo cuộc gọi trả về/lỗi theo cách mong đợi.

Bạn cũng cần phải biết về các bế tắc bảo mật, như một ví dụ về SQL injection, và kiểm tra những điều này.

Vì vậy, có, bạn cần phải lo lắng về việc kiểm tra các thuộc tính.

3

Mã thực sự tầm thường như getters và setters không có hành vi bổ sung hơn là thiết lập một trường riêng là quá mức cần thiết để kiểm tra. Trong 3.0 C# thậm chí có một số cú pháp đường, nơi trình biên dịch sẽ chăm sóc của trường tư nhân, do đó bạn không phải chương trình đó.

Tôi thường viết rất nhiều bài kiểm tra rất đơn giản xác minh hành vi tôi mong đợi từ các lớp học của mình. Ngay cả khi đó là những thứ đơn giản như thêm hai số. Tôi chuyển đổi rất nhiều giữa việc viết một bài kiểm tra đơn giản và viết một số dòng mã. Lý do cho điều này là tôi sau đó có thể thay đổi xung quanh mã mà không sợ tôi đã phá vỡ những điều tôi đã không nghĩ đến.

+0

Vui vì bạn đã đạt được một điểm tốt về nguyên tắc KISS .. Tôi thường có các bài kiểm tra theo nghĩa đen giống như 2-3 dòng mã, các bài kiểm tra nhỏ, đơn giản thực sự. Dễ dàng lúng túng và khó phá vỡ :) + 1'ed –

2

nói chung, khi phương pháp chỉ được xác định cho các giá trị nhất định, hãy kiểm tra các giá trị trên và trên đường viền của những gì có thể chấp nhận được. Nói cách khác, hãy chắc chắn rằng phương pháp của bạn thực hiện những gì nó phải làm, nhưng không có gì hơn. Điều này là quan trọng, bởi vì khi bạn sẽ thất bại, bạn muốn thất bại sớm.

Trong phân cấp thừa kế, hãy đảm bảo kiểm tra để tuân thủ LSP.

Kiểm tra getters và setters mặc định có vẻ không hữu ích đối với tôi, trừ khi bạn dự định thực hiện một số xác nhận sau này.

1

Tôi tin rằng thật ngớ ngẩn khi kiểm tra getters & người định cư khi họ chỉ thực hiện một thao tác đơn giản.Cá nhân tôi không viết các bài kiểm tra đơn vị phức tạp để bao gồm bất kỳ mẫu sử dụng nào. Tôi cố gắng viết đủ các bài kiểm tra để đảm bảo tôi đã xử lý hành vi thực thi bình thường và nhiều trường hợp lỗi mà tôi có thể nghĩ đến. Tôi sẽ viết nhiều bài kiểm tra đơn vị hơn như một phản hồi cho các báo cáo lỗi. Tôi sử dụng kiểm tra đơn vị để đảm bảo mã đáp ứng các yêu cầu và để thực hiện sửa đổi trong tương lai dễ dàng hơn. Tôi cảm thấy sẵn sàng hơn để thay đổi mã khi tôi biết rằng nếu tôi phá vỡ một cái gì đó một thử nghiệm sẽ thất bại.

1

Tôi sẽ viết một bài kiểm tra cho bất cứ điều gì mà bạn đang viết mã cho rằng nằm ngoài kiểm chứng của giao diện GUI.

Thông thường, bất kỳ logic nào tôi viết có bất kỳ logic nghiệp vụ nào tôi đặt bên trong một lớp logic hoặc lớp logic nghiệp vụ khác.

Sau đó viết các bài kiểm tra cho bất kỳ điều gì làm điều gì đó dễ thực hiện.

Lần đầu tiên, viết bài kiểm tra đơn vị cho từng phương pháp công khai trong "Lớp logic nghiệp vụ" của bạn.

Nếu tôi có một lớp học như thế này:

public class AccountService 
    { 
     public void DebitAccount(int accountNumber, double amount) 
     { 

     } 

     public void CreditAccount(int accountNumber, double amount) 
     { 

     } 

     public void CloseAccount(int accountNumber) 
     { 

     } 
    } 

Điều đầu tiên tôi sẽ làm trước khi tôi viết bất kỳ mã biết rằng tôi đã có những hành động để thực hiện sẽ được bắt đầu viết các bài kiểm tra đơn vị.

[TestFixture] 
    public class AccountServiceTests 
    { 
     [Test] 
     public void DebitAccountTest() 
     { 

     } 

     [Test] 
     public void CreditAccountTest() 
     { 

     } 

     [Test] 
     public void CloseAccountTest() 
     { 

     } 
    } 

Viết thử nghiệm để xác thực mã bạn đã viết để làm điều gì đó. Nếu bạn lặp qua một bộ sưu tập các thứ, và thay đổi một cái gì đó về mỗi người, hãy viết một bài kiểm tra làm điều tương tự và khẳng định rằng thực sự đã xảy ra.

Có rất nhiều cách tiếp cận khác bạn có thể thực hiện, cụ thể là Behavoir Driven Development (BDD), có liên quan nhiều hơn và không phải là nơi tuyệt vời để bắt đầu với kỹ năng kiểm tra đơn vị của bạn. Vì vậy, đạo đức của câu chuyện là, kiểm tra bất cứ điều gì làm bất cứ điều gì bạn có thể lo lắng, giữ cho các bài kiểm tra đơn vị kiểm tra những thứ cụ thể có kích thước nhỏ, rất nhiều bài kiểm tra là tốt.

Giữ logic nghiệp vụ của bạn bên ngoài lớp Giao diện người dùng để bạn có thể dễ dàng viết kiểm tra cho chúng và bạn sẽ tốt.

Tôi khuyên bạn nên TestDriven.Net hoặc ReSharper vì cả hai đều dễ dàng tích hợp vào Visual Studio.

1

nếu bạn cho rằng nó có thể bị hỏng, hãy viết bài kiểm tra. Tôi thường không kiểm tra setter/getter, nhưng cho phép nói rằng bạn tạo một tên cho User.Name, nối tên và họ, tôi sẽ viết một bài kiểm tra để nếu ai đó thay đổi thứ tự họ và tên, ít nhất anh ta sẽ biết ông đã thay đổi một cái gì đó đã được thử nghiệm.

1

Câu trả lời kinh điển là "kiểm tra mọi thứ có thể bị hỏng". Nếu bạn chắc chắn các thuộc tính sẽ không bị hỏng, đừng kiểm tra chúng.

Và sau khi một thứ gì đó được tìm thấy đã bị hỏng (bạn tìm thấy lỗi), rõ ràng điều đó có nghĩa là bạn cần phải kiểm tra nó. Viết một bài kiểm tra để tái tạo lỗi, xem nó không thành công, sau đó sửa lỗi, sau đó xem đoạn thử nghiệm.

3

Bạn nên kiểm tra mọi thứ. Ngay bây giờ bạn có getters và setters, nhưng một ngày bạn có thể thay đổi chúng một chút, có thể để làm xác nhận hoặc cái gì khác. Các bài kiểm tra bạn viết ngày hôm nay sẽ được sử dụng vào ngày mai để đảm bảo mọi thứ tiếp tục hoạt động như bình thường. Khi bạn viết bài kiểm tra, bạn nên quên những cân nhắc như "ngay bây giờ nó tầm thường". Trong một bối cảnh nhanh hoặc thử nghiệm, bạn nên kiểm tra giả định tái cấu trúc tương lai. Ngoài ra, bạn có thử đặt các giá trị thực sự kỳ lạ như chuỗi cực dài hay nội dung "xấu" khác không? Chà, bạn nên ... đừng bao giờ cho rằng mã của bạn có thể bị lạm dụng trong tương lai.

Nói chung tôi thấy rằng việc viết thử nghiệm người dùng mở rộng ở một bên, hết sức. Mặt khác, mặc dù nó luôn cung cấp cho bạn cái nhìn sâu sắc vô giá về cách ứng dụng của bạn hoạt động và giúp bạn vứt bỏ các giả định (và giả) dễ dàng (như: tên người dùng sẽ luôn có độ dài nhỏ hơn 1000 ký tự).

1

Tôi khuyên bạn nên viết nhiều bài kiểm tra cho các phương pháp Xác thực và Lưu. Ngoài trường hợp thành công (tất cả các tham số được cung cấp, mọi thứ đều được viết đúng, vv), rất tốt để có các kiểm tra cho các trường hợp lỗi khác nhau (tham số không chính xác hoặc thiếu, kết nối cơ sở dữ liệu không có sẵn nếu có, vv). Tôi khuyên bạn nên Pragmatic Unit Testing in C# with NUnit làm tài liệu tham khảo.

Như những người khác đã nêu, kiểm tra đơn vị cho getters và setters là quá mức cần thiết, trừ khi có logic điều kiện trong getters và setters của bạn.

3

Đối với các mô-đun đơn giản có thể kết thúc trong bộ công cụ, hoặc trong một loại nguồn mở của dự án, bạn nên kiểm tra càng nhiều càng tốt bao gồm cả getters và setters tầm thường. Điều bạn muốn ghi nhớ là tạo ra một bài kiểm tra đơn vị khi bạn viết một mô-đun cụ thể khá đơn giản và thẳng về phía trước. Thêm getters và setters là mã tối thiểu và có thể được xử lý mà không cần suy nghĩ nhiều. Tuy nhiên, khi mã của bạn được đặt trong một hệ thống lớn hơn, nỗ lực bổ sung này có thể bảo vệ bạn khỏi những thay đổi trong hệ thống cơ bản, chẳng hạn như thay đổi loại trong một lớp cơ sở. Kiểm tra everthing là cách tốt nhất để có một hồi quy đó là hoàn thành.

1

Trong khi có thể đoán chính xác vị trí mã của bạn cần kiểm tra, tôi thường nghĩ bạn cần số liệu để sao lưu dự đoán này. Kiểm tra đơn vị trong chế độ xem của tôi đi đôi với các chỉ số bao phủ mã.

Mã với nhiều thử nghiệm nhưng phạm vi bảo hiểm nhỏ chưa được kiểm tra tốt. Điều đó nói rằng, mã với phạm vi bảo hiểm 100% nhưng không thử nghiệm các trường hợp ràng buộc và lỗi cũng không phải là tuyệt vời.

Bạn muốn cân bằng giữa mức độ phù hợp cao (tối thiểu 90%) và dữ liệu đầu vào biến.

Hãy nhớ kiểm tra "rác trong"!

Ngoài ra, kiểm tra đơn vị không phải là đơn vị kiểm tra trừ khi nó kiểm tra lỗi. Các bài kiểm tra đơn vị không có xác nhận hoặc được đánh dấu bằng các trường hợp ngoại lệ đã biết sẽ chỉ kiểm tra mã không chết khi chạy!

Bạn cần thiết kế các thử nghiệm của mình để chúng luôn báo cáo lỗi hoặc dữ liệu không mong muốn/không mong muốn!

1

Nó làm cho mã của chúng tôi tốt hơn ... thời gian!

Một điều mà các nhà phát triển phần mềm mà chúng tôi quên khi thực hiện phát triển thử nghiệm là mục đích đằng sau hành động của chúng tôi. Nếu một thử nghiệm đơn vị được viết sau khi mã sản xuất đã có sẵn, giá trị của thử nghiệm sẽ giảm dần (nhưng không hoàn toàn bị mất).

Trong tinh thần thực sự để kiểm tra đơn vị, các thử nghiệm này là không phải là chủ yếu ở đó để "kiểm tra" thêm mã của chúng tôi; hoặc để có được độ bao phủ mã tốt hơn 90% -100%. Đây là tất cả các lợi ích cạnh tranh rìa bằng văn bản các bài kiểm tra đầu tiên. Khoản hoàn trả lớn là mã sản xuất của chúng tôi kết thúc được viết tốt hơn nhiều do quá trình TDD tự nhiên.

Để giúp tốt hơn giao tiếp ý tưởng này, sau đây có thể hữu ích trong việc đọc:

The Flawed Theory of Unit Tests
Purposeful Software Development

Nếu chúng ta cảm thấy rằng hành động viết nhiều đơn vị kiểm tra là những gì giúp chúng ta đạt được một sản phẩm chất lượng cao hơn, sau đó chúng tôi có thể bị Cargo Cult phát triển theo hướng thử nghiệm.

+0

Tôi không đồng ý với khẳng định rằng các bài kiểm tra đơn vị không có giá trị sau khi mã sản xuất đã có sẵn. Các xác nhận như vậy không tính đến tiện ích của chúng trong việc tái tạo các điều kiện lỗi được tìm thấy trong sản xuất hoặc trong sự hiểu biết về mã được thừa kế từ một nhà phát triển hoặc nhóm trước đó. –

+0

Tôi có thể gặp lỗi không chính xác. Tôi không có nghĩa là các bài kiểm tra đơn vị không có giá trị sau khi mã sản xuất được đặt ra. Tuy nhiên, giá trị của họ giảm. Lợi ích lớn nhất đối với thử nghiệm đơn vị xuất phát từ ma thuật vốn có xảy ra khi chúng tôi cho phép họ thúc đẩy phát triển sản xuất của chúng tôi. –

0

Tôi thứ hai kiểm tra mọi thứ có thể có thể vi phạmkhông viết các kiểm tra ngớ ngẩn. Nhưng nguyên lý quan trọng nhất là kiểm tra bất cứ điều gì bạn tìm thấy bị hỏng: nếu một số phương thức hoạt động một cách kỳ quặc viết một bài kiểm tra để phác thảo tập dữ liệu khiến nó thất bại, sau đó sửa lỗi và xem thanh màu xanh lá cây. Ngoài ra kiểm tra các giá trị dữ liệu "ranh giới" (null, 0, MAX_INT, danh sách trống, bất cứ điều gì).

0

Khi viết bài kiểm tra đơn vị, hoặc thực sự kiểm tra bất kỳ, bạn xác định những gì cần kiểm tra bằng cách xem xét các điều kiện biên của những gì bạn đang thử nghiệm. Ví dụ, bạn có một hàm gọi là is_prime. May mắn thay, nó làm những gì tên của nó hàm ý và cho bạn biết liệu đối tượng nguyên là nguyên tố hay không. Đối với điều này tôi giả sử bạn đang sử dụng các đối tượng. Bây giờ, chúng ta sẽ cần phải kiểm tra xem các kết quả hợp lệ đã xảy ra cho một phạm vi đã biết của các đối tượng nguyên tố và không chính. Đó là điểm khởi đầu của bạn.

Về cơ bản, hãy xem điều gì sẽ xảy ra với chức năng, phương pháp, chương trình hoặc tập lệnh, và sau đó tại những gì chắc chắn không phải xảy ra với cùng mã đó. Đó là cơ sở cho thử nghiệm của bạn. Chỉ cần chuẩn bị để sửa đổi các bài kiểm tra của bạn khi bạn hiểu rõ hơn về những gì nên đang xảy ra với mã của bạn.

4

Một câu trả lời hợp lý khác. Điều này, tôi tin rằng, từ Ron Jeffries:

Chỉ kiểm tra mã mà bạn muốn làm việc.

0

Mã viết không có giá trị luôn là ý tưởng tồi. Vì thử nghiệm được đề xuất không thêm giá trị cho dự án của bạn (hoặc rất gần với nó). Sau đó, bạn đang lãng phí thời gian quý báu mà bạn có thể chi tiêu viết mã thực sự mang lại giá trị.

36

này đã cho tôi vào kiểm tra đơn vị và nó khiến tôi rất hạnh phúc

Chúng tôi chỉ mới bắt đầu để làm kiểm tra đơn vị. Trong một thời gian dài tôi biết nó sẽ là tốt để bắt đầu làm điều đó nhưng tôi không có ý tưởng làm thế nào để bắt đầu và quan trọng hơn những gì để kiểm tra.

Sau đó, chúng tôi đã phải viết lại một đoạn mã quan trọng trong chương trình kế toán của chúng tôi. Phần này rất phức tạp vì nó liên quan đến rất nhiều kịch bản khác nhau. Phần tôi đang nói đến là phương thức thanh toán hóa đơn bán hàng và/hoặc mua hàng đã được nhập vào hệ thống kế toán.

Tôi chỉ không biết bắt đầu viết mã như thế nào, vì có quá nhiều tùy chọn thanh toán khác nhau. Hóa đơn có thể là 100 đô la nhưng khách hàng chỉ chuyển 99 đô la. Có thể bạn đã gửi hóa đơn bán hàng cho khách hàng nhưng bạn cũng đã mua từ khách hàng đó. Vì vậy, bạn đã bán anh ta với giá 300 đô la nhưng bạn đã mua với giá 100 đô la. Bạn có thể mong đợi khách hàng của bạn trả cho bạn 200 đô la để thanh toán số dư. Và nếu bạn bán với giá 500 đô la nhưng khách hàng chỉ trả cho bạn 250 đô la?

Vì vậy, tôi đã có một vấn đề rất phức tạp để giải quyết với nhiều khả năng rằng một kịch bản sẽ hoạt động hoàn hảo nhưng sẽ sai trên một loại kết hợp invocie/thanh toán khác.

Đây là nơi thử nghiệm đơn vị được giải cứu.

Tôi bắt đầu viết (bên trong mã kiểm tra) một phương pháp để tạo danh sách hóa đơn, cả cho bán hàng và mua hàng. Sau đó, tôi đã viết một phương pháp thứ hai để tạo thanh toán thực tế. Thông thường, người dùng sẽ nhập thông tin đó thông qua giao diện người dùng.

Sau đó, tôi đã tạo TestMethod đầu tiên, thử nghiệm một khoản thanh toán rất đơn giản của một hóa đơn mà không có bất kỳ khoản chiết khấu thanh toán nào. Tất cả các hành động trong hệ thống sẽ xảy ra khi một khoản thanh toán qua ngân hàng sẽ được lưu vào cơ sở dữ liệu. Như bạn thấy, tôi đã tạo một hóa đơn, tạo một khoản thanh toán (một giao dịch ngân hàng) và lưu giao dịch vào đĩa. Trong xác nhận của tôi, tôi đặt những con số chính xác sẽ kết thúc trong giao dịch Ngân hàng và trong Hóa đơn được liên kết. Tôi kiểm tra số lần thanh toán, số tiền thanh toán, số tiền chiết khấu và số dư của hóa đơn sau giao dịch.

Sau khi chạy thử, tôi sẽ chuyển đến cơ sở dữ liệu và kiểm tra kỹ xem tôi có dự kiến ​​gì không.

Sau Tôi đã viết bài kiểm tra, tôi bắt đầu viết mã phương thức thanh toán (một phần của lớp BankHeader). Trong mã, tôi chỉ làm phiền với mã để thực hiện lần kiểm tra đầu tiên. Tôi chưa nghĩ về các kịch bản khác, phức tạp hơn.

Tôi đã chạy thử nghiệm đầu tiên, sửa lỗi nhỏ cho đến khi thử nghiệm của tôi vượt qua.

Sau đó, tôi bắt đầu viết bài kiểm tra thứ hai, lần này làm việc với chiết khấu thanh toán. Sau khi tôi viết bài kiểm tra, tôi đã sửa đổi phương thức thanh toán để hỗ trợ giảm giá.

Trong khi kiểm tra tính chính xác với chiết khấu thanh toán, tôi cũng đã thử nghiệm thanh toán đơn giản. Cả hai bài kiểm tra nên vượt qua tất nhiên.

Sau đó, tôi làm việc theo cách của mình xuống các tình huống phức tạp hơn.

1) Hãy nghĩ về một kịch bản mới

2) Viết một bài kiểm tra cho kịch bản mà

3) Chạy rằng thử nghiệm duy nhất để xem nếu nó sẽ vượt qua

4) Nếu nó didn' Tôi muốn gỡ lỗi và sửa đổi mã cho đến khi nó vượt qua.

5) Trong khi sửa đổi mã tôi tiếp tục chạy tất cả các thử nghiệm

Đây là cách tôi quản lý để tạo phương thức thanh toán rất phức tạp của mình. Nếu không có thử nghiệm đơn vị, tôi không biết bắt đầu viết mã như thế nào, vấn đề dường như quá tải. Với thử nghiệm tôi có thể bắt đầu với một phương pháp đơn giản và mở rộng nó từng bước với sự đảm bảo rằng các kịch bản đơn giản hơn sẽ vẫn hoạt động.

Tôi chắc chắn rằng việc sử dụng kiểm tra đơn vị đã tiết kiệm cho tôi một vài ngày (hoặc vài tuần) mã hóa và ít nhiều đảm bảo tính chính xác của phương pháp của tôi.

Nếu sau này tôi nghĩ về một tình huống mới, tôi có thể thêm nó vào các thử nghiệm để xem nó có đang hoạt động hay không. Nếu không, tôi có thể sửa đổi mã nhưng vẫn đảm bảo các tình huống khác vẫn hoạt động chính xác. Điều này sẽ tiết kiệm ngày và ngày trong giai đoạn sửa chữa và sửa lỗi.

Có, mã thậm chí thử nghiệm vẫn có thể có lỗi nếu người dùng làm những việc bạn không nghĩ đến hoặc ngăn cản ông làm

Dưới đây là một số bài kiểm tra tôi tạo ra để thử nghiệm phương thức thanh toán của tôi.

public class TestPayments 
{ 
    InvoiceDiaryHeader invoiceHeader = null; 
    InvoiceDiaryDetail invoiceDetail = null; 
    BankCashDiaryHeader bankHeader = null; 
    BankCashDiaryDetail bankDetail = null; 



    public InvoiceDiaryHeader CreateSales(string amountIncVat, bool sales, int invoiceNumber, string date) 
    { 
     ...... 
     ...... 
    } 

    public BankCashDiaryHeader CreateMultiplePayments(IList<InvoiceDiaryHeader> invoices, int headerNumber, decimal amount, decimal discount) 
    { 
     ...... 
     ...... 
     ...... 
    } 


    [TestMethod] 
    public void TestSingleSalesPaymentNoDiscount() 
    { 
     IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>(); 
     list.Add(CreateSales("119", true, 1, "01-09-2008")); 
     bankHeader = CreateMultiplePayments(list, 1, 119.00M, 0); 
     bankHeader.Save(); 

     Assert.AreEqual(1, bankHeader.BankCashDetails.Count); 
     Assert.AreEqual(1, bankHeader.BankCashDetails[0].Payments.Count); 
     Assert.AreEqual(119M, bankHeader.BankCashDetails[0].Payments[0].PaymentAmount); 
     Assert.AreEqual(0M, bankHeader.BankCashDetails[0].Payments[0].PaymentDiscount); 
     Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[0].InvoiceHeader.Balance); 
    } 

    [TestMethod] 
    public void TestSingleSalesPaymentDiscount() 
    { 
     IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>(); 
     list.Add(CreateSales("119", true, 2, "01-09-2008")); 
     bankHeader = CreateMultiplePayments(list, 2, 118.00M, 1M); 
     bankHeader.Save(); 

     Assert.AreEqual(1, bankHeader.BankCashDetails.Count); 
     Assert.AreEqual(1, bankHeader.BankCashDetails[0].Payments.Count); 
     Assert.AreEqual(118M, bankHeader.BankCashDetails[0].Payments[0].PaymentAmount); 
     Assert.AreEqual(1M, bankHeader.BankCashDetails[0].Payments[0].PaymentDiscount); 
     Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[0].InvoiceHeader.Balance); 
    } 

    [TestMethod] 
    [ExpectedException(typeof(ApplicationException))] 
    public void TestDuplicateInvoiceNumber() 
    { 
     IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>(); 
     list.Add(CreateSales("100", true, 2, "01-09-2008")); 
     list.Add(CreateSales("200", true, 2, "01-09-2008")); 

     bankHeader = CreateMultiplePayments(list, 3, 300, 0); 
     bankHeader.Save(); 
     Assert.Fail("expected an ApplicationException"); 
    } 

    [TestMethod] 
    public void TestMultipleSalesPaymentWithPaymentDiscount() 
    { 
     IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>(); 
     list.Add(CreateSales("119", true, 11, "01-09-2008")); 
     list.Add(CreateSales("400", true, 12, "02-09-2008")); 
     list.Add(CreateSales("600", true, 13, "03-09-2008")); 
     list.Add(CreateSales("25,40", true, 14, "04-09-2008")); 

     bankHeader = CreateMultiplePayments(list, 5, 1144.00M, 0.40M); 
     bankHeader.Save(); 

     Assert.AreEqual(1, bankHeader.BankCashDetails.Count); 
     Assert.AreEqual(4, bankHeader.BankCashDetails[0].Payments.Count); 
     Assert.AreEqual(118.60M, bankHeader.BankCashDetails[0].Payments[0].PaymentAmount); 
     Assert.AreEqual(400, bankHeader.BankCashDetails[0].Payments[1].PaymentAmount); 
     Assert.AreEqual(600, bankHeader.BankCashDetails[0].Payments[2].PaymentAmount); 
     Assert.AreEqual(25.40M, bankHeader.BankCashDetails[0].Payments[3].PaymentAmount); 

     Assert.AreEqual(0.40M, bankHeader.BankCashDetails[0].Payments[0].PaymentDiscount); 
     Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[1].PaymentDiscount); 
     Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[2].PaymentDiscount); 
     Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[3].PaymentDiscount); 

     Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[0].InvoiceHeader.Balance); 
     Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[1].InvoiceHeader.Balance); 
     Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[2].InvoiceHeader.Balance); 
     Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[3].InvoiceHeader.Balance); 
    } 

    [TestMethod] 
    public void TestSettlement() 
    { 
     IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>(); 
     list.Add(CreateSales("300", true, 43, "01-09-2008")); //Sales 
     list.Add(CreateSales("100", false, 6453, "02-09-2008")); //Purchase 

     bankHeader = CreateMultiplePayments(list, 22, 200, 0); 
     bankHeader.Save(); 

     Assert.AreEqual(1, bankHeader.BankCashDetails.Count); 
     Assert.AreEqual(2, bankHeader.BankCashDetails[0].Payments.Count); 
     Assert.AreEqual(300, bankHeader.BankCashDetails[0].Payments[0].PaymentAmount); 
     Assert.AreEqual(-100, bankHeader.BankCashDetails[0].Payments[1].PaymentAmount); 
     Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[0].InvoiceHeader.Balance); 
     Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[1].InvoiceHeader.Balance); 
    } 
+1

Tìm thấy lỗi trong bài kiểm tra đơn vị của bạn! Bạn lặp lại dòng này thay vì bao gồm 2 trong một trong số chúng: 'Assert.AreEqual (0, bankHeader.BankCashDetails [0] .Payments [3] .InvoiceHeader.Balance);' –

+0

Ví dụ tuyệt vời !!! – Karim

+1

Bạn nói: "Sau khi chạy thử nghiệm, tôi sẽ đi đến cơ sở dữ liệu và kiểm tra lại nếu những gì tôi mong đợi đã có." Đây là một ví dụ tốt về kiểm tra tích hợp giữa các thành phần của hệ thống của bạn - không phải là một bài kiểm tra đơn vị riêng biệt của một đoạn mã duy nhất. – JTech

0

Nguyên tắc tốt nhất mà tôi đã nhìn thấy là kiểm tra mọi thứ bạn không thể biết trong nháy mắt, chắc chắn, sẽ hoạt động bình thường. Bất cứ điều gì nhiều hơn và bạn gió lên kiểm tra ngôn ngữ/môi trường.

4

Câu hỏi này có vẻ là một câu hỏi về việc người nào vẽ đường kẻ trên phương pháp nào được kiểm tra và không.

Các bộ định vị và getters để gán giá trị đã được tạo ra với sự nhất quán và tăng trưởng trong tương lai, và thấy trước một thời gian xuống đường bộ/getter có thể phát triển thành các hoạt động phức tạp hơn. Nó sẽ có ý nghĩa để đặt thử nghiệm đơn vị của những phương pháp đó tại chỗ, cũng vì lợi ích của sự nhất quán và tăng trưởng trong tương lai.

Độ tin cậy của mã, đặc biệt trong khi đang trải qua thay đổi để thêm chức năng bổ sung, là mục tiêu chính. Tôi không biết bất cứ ai từng bị sa thải bao gồm những người định cư/getters trong phương pháp thử nghiệm, nhưng tôi chắc chắn có tồn tại những người muốn họ thử nghiệm các phương pháp mà họ đã biết hoặc có thể gọi lại đơn giản. còn trường hợp.

Có thể một thành viên khác của nhóm đã mở rộng các phương pháp thiết lập/nhận để bao gồm logic hiện cần được kiểm tra nhưng sau đó không tạo các thử nghiệm. Nhưng bây giờ mã của bạn đang gọi các phương thức này và bạn không biết chúng đã thay đổi và cần kiểm tra sâu, và thử nghiệm bạn làm trong phát triển và QA không kích hoạt lỗi, nhưng dữ liệu kinh doanh thực tế vào ngày phát hành đầu tiên kích hoạt nó.

Hai đồng đội bây giờ sẽ tranh luận về việc ai đã đánh bóng và không đưa vào các bài kiểm tra đơn vị khi bộ/được biến đổi để bao gồm logic có thể thất bại nhưng không được kiểm tra đơn vị. Các đồng đội ban đầu đã viết các thiết lập/được sẽ có một thời gian dễ dàng hơn ra khỏi này sạch nếu các bài kiểm tra được thực hiện từ một ngày trên các thiết lập đơn giản/được.

ý kiến ​​của tôi là một vài phút "lãng phí" thời gian bao gồm tất cả các phương pháp thử nghiệm đơn vị, thậm chí tầm thường, có thể tiết kiệm ngày đau đầu xuống đường và mất tiền/danh tiếng của doanh nghiệp và mất công việc của ai đó.

Và thực tế là bạn đã bọc các phương pháp tầm thường với các bài kiểm tra đơn vị có thể được nhìn thấy bởi người bạn cùng lớp đó khi họ thay đổi các phương pháp tầm thường thành những người không tầm thường và nhắc họ cập nhật bài kiểm tra, và bây giờ không ai gặp rắc rối vì khiếm khuyết đã được đưa ra từ việc đạt được sản xuất.

Cách chúng tôi viết mã và kỷ luật có thể được nhìn thấy từ mã của chúng tôi, có thể giúp người khác.

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