Không nên kiểm tra đơn vị sử dụng phương pháp của riêng tôi?


83

Hôm nay tôi đang xem video " JUnit basics" và tác giả nói rằng khi thử nghiệm một phương thức nhất định trong chương trình của bạn, bạn không nên sử dụng các phương pháp khác của riêng mình trong quy trình.

Để cụ thể hơn, ông đã nói về việc thử nghiệm một số phương pháp tạo bản ghi lấy tên và họ cho các đối số và nó đã sử dụng chúng để tạo các bản ghi trong một bảng nhất định. Nhưng ông tuyên bố rằng trong quá trình thử nghiệm phương pháp này, ông không nên sử dụng các phương pháp DAO khác của mình để truy vấn cơ sở dữ liệu để kiểm tra kết quả cuối cùng (để kiểm tra xem bản ghi đó có thực sự được tạo với đúng dữ liệu không). Ông tuyên bố rằng vì điều đó, ông nên viết mã JDBC bổ sung để truy vấn cơ sở dữ liệu và kiểm tra kết quả.

Tôi nghĩ rằng tôi hiểu tinh thần của yêu cầu của anh ấy: bạn không muốn trường hợp thử nghiệm của một phương pháp phụ thuộc vào tính chính xác của các phương thức khác (trong trường hợp này là phương pháp DAO) và điều này được thực hiện bằng cách viết (một lần nữa) xác thực của bạn / mã hỗ trợ (cần cụ thể hơn và tập trung hơn, do đó, mã đơn giản hơn).

Tuy nhiên, những tiếng nói trong đầu tôi bắt đầu phản đối với các đối số như sao chép mã, những nỗ lực bổ sung không cần thiết, v.v. Bạn có thể sử dụng một số phương pháp trong khi thử nghiệm các phương pháp khác không? Nếu một trong số họ không làm những gì nó được yêu cầu, thì trường hợp thử nghiệm của chính nó sẽ thất bại, và chúng tôi có thể sửa nó và chạy lại pin thử nghiệm. Không cần sao chép mã (ngay cả khi mã trùng lặp có phần đơn giản hơn) hoặc lãng phí nỗ lực.

Tôi có một cảm giác mạnh mẽ về điều này vì một số ứng dụng Excel - VBA gần đây tôi đã viết (được kiểm tra đơn vị chính xác nhờ Rubberduck cho VBA ), trong đó áp dụng đề xuất này có nghĩa là sẽ có thêm rất nhiều công việc bổ sung, không có lợi ích nhận thức.

Bạn có thể vui lòng chia sẻ những hiểu biết của bạn về điều này?


79
Thật kỳ lạ khi thấy một bài kiểm tra đơn vị liên quan đến cơ sở dữ liệu
Richard Tingle

4
IMO thật tốt khi gọi các lớp khác IFF là họ đủ nhanh. Mock bất cứ điều gì phải đi vào đĩa hoặc qua mạng. Không có ý nghĩa trong việc chế nhạo IMO lớp ol 'đơn giản.
RubberDuck

2
Có một liên kết đến video này?
candied_orange

17
" được kiểm tra đúng đơn vị nhờ Rubberduck cho VBA " - thưa ngài, vừa làm cho ngày của tôi. Tôi đã sửa lỗi chính tả và chỉnh sửa nó từ "RubberDuck" thành "Rubberduck", nhưng tôi cảm thấy như một kẻ gửi thư rác đang làm điều đó và thêm một liên kết đến Rubberduckvba.com (Tôi sở hữu tên miền và đồng sở hữu dự án với @RubberDuck) - vì vậy tôi sẽ chỉ bình luận ở đây để thay thế. Dù sao, thật tuyệt vời khi thấy mọi người thực sự sử dụng công cụ chịu trách nhiệm cho hầu hết các đêm mất ngủ của tôi trong phần hai năm qua! =)
Mathieu Guindon

4
@ Mat'sMug và RubberDuck Tôi thích những gì bạn đang làm với Rubberduck. Hãy giữ nó lên. Chắc chắn cuộc sống của tôi dễ dàng hơn nhờ nó (tôi tình cờ thực hiện rất nhiều chương trình và nguyên mẫu nhỏ trong Excel VBA). BTW, đề cập đến Rubberduck trong bài viết của tôi chỉ là tôi đang cố gắng trở nên tốt đẹp với RubberDuck, điều này đã trở nên tốt đẹp đối với tôi ở đây trong PE. :)
carlossierra

Câu trả lời:


186

Tinh thần yêu sách của ông thực sự là chính xác. Quan điểm của các bài kiểm tra đơn vị là cô lập mã, kiểm tra nó không phụ thuộc, để bất kỳ hành vi sai lầm nào cũng có thể được nhận ra nhanh chóng ở nơi nó đang xảy ra.

Như đã nói, thử nghiệm đơn vị là một công cụ, và nó có nghĩa là để phục vụ mục đích của bạn, nó không phải là một bàn thờ để được cầu nguyện. Đôi khi, điều đó có nghĩa là để lại sự phụ thuộc vì chúng hoạt động đủ đáng tin cậy và bạn không muốn làm phiền họ, đôi khi điều đó có nghĩa là một số bài kiểm tra đơn vị của bạn thực sự khá gần nếu không thực sự kiểm tra tích hợp.

Cuối cùng, bạn không được chấm điểm về nó, điều quan trọng là sản phẩm cuối cùng của phần mềm đang được thử nghiệm, nhưng bạn sẽ phải chú ý khi bạn bẻ cong các quy tắc và quyết định khi nào sự đánh đổi có giá trị.


117
Hoan hô chủ nghĩa thực dụng.
Robert Harvey

6
Tôi sẽ nói thêm rằng đó không phải là độ tin cậy nhiều vì tốc độ là vấn đề dẫn đến việc loại bỏ các phụ thuộc. Bài kiểm tra trong thần chú cô lập rất hấp dẫn tuy nhiên lập luận này thường bị bỏ qua.
Michael Durrant

4
"... thử nghiệm đơn vị là một công cụ, và nó có nghĩa là để phục vụ mục đích của bạn, nó không phải là một bàn thờ để được cầu nguyện." - đây!
Wayne Conrad

15
"Không phải là một bàn thờ để được cầu nguyện" - huấn luyện viên TDD tức giận đến!
Den

5
@ jpmc26: thậm chí tệ hơn nữa là bạn không muốn tất cả các bài kiểm tra đơn vị của mình vượt qua vì họ đã xử lý chính xác dịch vụ web bị hỏng, đây là hành vi hợp lệ và chính xác, nhưng thực sự không bao giờ thực hiện mã khi nó hoạt động! Khi bạn còn sơ khai, bạn có thể chọn xem "lên" hay "xuống" và kiểm tra cả hai.
Steve Jessop

36

Tôi nghĩ rằng điều này đi xuống thuật ngữ. Đối với nhiều người, "kiểm thử đơn vị" là một điều rất cụ thể và theo định nghĩa không thể có điều kiện đạt / không phụ thuộc vào bất kỳ mã nào bên ngoài đơn vị (phương thức, chức năng, v.v.) đang được kiểm tra. Điều này sẽ bao gồm tương tác với một cơ sở dữ liệu.

Đối với những người khác, thuật ngữ "kiểm thử đơn vị" lỏng lẻo hơn nhiều và bao gồm bất kỳ loại thử nghiệm tự động nào, bao gồm cả mã kiểm tra kiểm tra các phần tích hợp của ứng dụng.

Một thử nghiệm thuần túy (nếu tôi có thể sử dụng thuật ngữ đó) có thể gọi đó là thử nghiệm tích hợp , được phân biệt với thử nghiệm đơn vị trên cơ sở thử nghiệm phụ thuộc vào nhiều hơn một đơn vị mã thuần túy .

Tôi nghi ngờ rằng bạn đang sử dụng phiên bản lỏng hơn của thuật ngữ "kiểm tra đơn vị" và thực sự đang đề cập đến "kiểm tra tích hợp".

Sử dụng các định nghĩa đó, bạn không nên phụ thuộc vào mã bên ngoài đơn vị được kiểm tra trong "kiểm tra đơn vị". Tuy nhiên, trong "kiểm tra tích hợp", việc viết một bài kiểm tra thực hiện một số đoạn mã cụ thể và sau đó kiểm tra cơ sở dữ liệu để biết các tiêu chí thông qua là hoàn toàn hợp lý.

Cho dù bạn nên phụ thuộc vào kiểm tra tích hợp hoặc kiểm tra đơn vị hoặc cả hai là một chủ đề thảo luận lớn hơn nhiều.


Bạn đúng về sự nghi ngờ của bạn. Tôi đang sử dụng sai các điều khoản và bây giờ tôi có thể thấy làm thế nào mỗi loại bài kiểm tra có thể được xử lý phù hợp hơn. Cảm ơn!
carlossierra

11
"Đối với người khác, thuật ngữ" kiểm tra đơn vị "lỏng lẻo hơn nhiều" - ngoài bất kỳ điều gì khác, cái gọi là "khung kiểm tra đơn vị" là một cách thực sự thuận tiện để tổ chức và chạy các bài kiểm tra cấp cao hơn ;-)
Steve Jessop

1
Thay vì phân biệt "thuần túy" và "lỏng lẻo", chứa đầy ý nghĩa, tôi đề nghị phân biệt giữa những người xem "đơn vị", "phụ thuộc", v.v. từ góc độ tên miền (ví dụ: "xác thực" sẽ được tính là một đơn vị, "cơ sở dữ liệu" sẽ được tính là một phụ thuộc, v.v.) so với những người xem chúng từ góc độ ngôn ngữ lập trình (ví dụ: các phương thức là các đơn vị, các lớp là các phụ thuộc). Tôi thấy rằng việc xác định ý nghĩa của các cụm từ như "đơn vị được kiểm tra" có thể biến các đối số ("Bạn sai!") Thành các cuộc thảo luận ("Đây có phải là mức độ chi tiết đúng không?").
Warbo

1
@EricKing Tất nhiên, đối với phần lớn những người trong danh mục đầu tiên của bạn, ý tưởng liên quan đến cơ sở dữ liệu trong tất cả các bài kiểm tra đơn vị là anathema, cho dù bạn sử dụng DAO hay truy cập trực tiếp vào cơ sở dữ liệu.
Periata Breatta

1
@AmaniKilumanga Câu hỏi về cơ bản là "ai đó nói rằng tôi không nên làm điều này trong các bài kiểm tra đơn vị nhưng tôi làm nó trong các bài kiểm tra đơn vị và tôi nghĩ nó ổn. Điều đó có ổn không?" Và câu trả lời của tôi là "Có, nhưng hầu hết mọi người sẽ gọi đó là kiểm tra tích hợp thay vì kiểm tra đơn vị.". Theo như câu hỏi của bạn, tôi không biết ý của bạn là gì "có thể kiểm tra tích hợp sử dụng các phương thức mã sản xuất không?".
Eric King

7

Câu trả lời là có hoặc không...

Các thử nghiệm độc đáo thực hiện trong sự cô lập là một điều tuyệt đối phải làm vì nó cho phép bạn đặt ra công việc cơ bản rằng mã cấp thấp của bạn đang hoạt động phù hợp. Nhưng trong việc mã hóa các thư viện lớn hơn, bạn cũng sẽ tìm thấy các khu vực mã sẽ yêu cầu bạn phải kiểm tra các đơn vị chéo.

Các thử nghiệm đơn vị chéo này tốt cho phạm vi bảo hiểm mã và khi thử nghiệm kết thúc chức năng nhưng chúng đi kèm với một vài nhược điểm bạn cần lưu ý:

  • Nếu không có kiểm tra độc lập để xác nhận những gì đang vi phạm, thử nghiệm "đơn vị chéo" không thành công sẽ yêu cầu khắc phục sự cố bổ sung để xác định chính xác những gì sai với mã của bạn
  • Dựa quá nhiều vào các bài kiểm tra đơn vị chéo có thể giúp bạn thoát khỏi suy nghĩ hợp đồng mà bạn phải luôn có khi viết mã Hướng đối tượng RẮN. Các thử nghiệm biệt lập thường có ý nghĩa vì các đơn vị của bạn chỉ nên thực hiện một hành động cơ bản.
  • Thử nghiệm từ đầu đến cuối là mong muốn nhưng có thể nguy hiểm nếu thử nghiệm yêu cầu bạn ghi vào cơ sở dữ liệu hoặc thực hiện một số hành động mà bạn không muốn xảy ra trong môi trường sản xuất. Đây là một trong nhiều lý do tại sao các khung mô phỏng như Mockito rất phổ biến vì nó cho phép bạn giả mạo một đối tượng và bắt chước thử nghiệm kết thúc để kết thúc mà không thực sự thay đổi thứ gì đó bạn không nên.

Vào cuối ngày, bạn muốn có một số cả hai .. rất nhiều bài kiểm tra bẫy chức năng cấp thấp và một số bài kiểm tra kết thúc chức năng. Tập trung vào lý do tại sao bạn đang viết bài kiểm tra ở nơi đầu tiên. Họ ở đó để cung cấp cho bạn sự tự tin rằng mã của bạn đang thực hiện theo cách bạn mong đợi. Bất cứ điều gì bạn cần làm để thực hiện điều đó là tốt.

Điều đáng buồn nhưng sự thật là nếu bạn đang sử dụng các bài kiểm tra tự động thì bạn đã có rất nhiều nhà phát triển. Thực hành thử nghiệm tốt là điều đầu tiên trượt khi một nhóm phát triển phải đối mặt với thời hạn khó khăn. Vì vậy, miễn là bạn đang sử dụng súng và viết các bài kiểm tra đơn vị phản ánh có ý nghĩa về cách mã của bạn sẽ thực hiện, tôi sẽ không ám ảnh về việc các bài kiểm tra của bạn "thuần túy" như thế nào.


4

Một vấn đề với việc sử dụng các phương thức đối tượng khác để kiểm tra một điều kiện là bạn sẽ bỏ lỡ các lỗi triệt tiêu lẫn nhau. Quan trọng hơn, bạn đang bỏ lỡ nỗi đau của việc thực hiện bài kiểm tra khó khăn và nỗi đau đó đang dạy cho bạn một vài điều về mã cơ bản của bạn. Thử nghiệm đau bây giờ có nghĩa là duy trì đau đớn sau này.

Làm cho các đơn vị của bạn nhỏ hơn, chia lớp, tái cấu trúc và thiết kế lại cho đến khi dễ kiểm tra hơn mà không cần thực hiện lại phần còn lại của đối tượng. Nhận một số trợ giúp nếu bạn nghĩ rằng mã hoặc bài kiểm tra của bạn không thể được đơn giản hóa thêm nữa. Hãy thử nghĩ về một đồng nghiệp dường như luôn gặp may mắn và nhận được các bài tập dễ kiểm tra sạch sẽ. Yêu cầu anh ấy hoặc cô ấy giúp đỡ, bởi vì đó không phải là may mắn.


1
Chìa khóa ở đây là trong đơn vị. Nếu bạn cần thực hiện các cuộc gọi đến các quy trình và quy trình khác, thì đó sẽ không phải là một đơn vị. Nếu nhiều cuộc gọi được thực hiện và nhiều bước cần phải được xác thực, thì nếu đó là một đoạn mã lớn hơn một đơn vị, hãy chia nó thành các phần nhỏ hơn bao gồm một đoạn logic. Thông thường, một cuộc gọi DB cũng sẽ bị chế giễu hoặc DB trong bộ nhớ sẽ được sử dụng trong kiểm tra đơn vị khi truy cập DB thực và cần hoàn tác dữ liệu sau khi kiểm tra.
dlb

1

Nếu đơn vị chức năng đang được kiểm tra là 'là dữ liệu được lưu trữ liên tục và có thể truy xuất được', thì tôi sẽ có bài kiểm tra đơn vị - lưu trữ vào cơ sở dữ liệu thực, phá hủy mọi đối tượng giữ tham chiếu đến cơ sở dữ liệu, sau đó gọi mã để tìm nạp đối tượng trở lại.

Việc kiểm tra xem một bản ghi được tạo trong cơ sở dữ liệu dường như có liên quan đến các chi tiết triển khai của cơ chế lưu trữ hơn là kiểm tra đơn vị chức năng tiếp xúc với phần còn lại của hệ thống.

Bạn có thể muốn rút ngắn kiểm tra để cải thiện hiệu suất bằng cơ sở dữ liệu giả, nhưng tôi đã có các nhà thầu thực hiện chính xác điều đó và để lại khi kết thúc hợp đồng với một hệ thống vượt qua các thử nghiệm như vậy, nhưng thực tế không lưu trữ bất cứ điều gì trong cơ sở dữ liệu giữa các hệ thống khởi động lại.

Bạn có thể tranh luận liệu 'đơn vị' trong kiểm tra đơn vị biểu thị một 'đơn vị mã' hoặc 'đơn vị chức năng', chức năng có thể được tạo bởi nhiều đơn vị mã trong buổi hòa nhạc. Tôi không thấy đây là một sự khác biệt hữu ích - những câu hỏi tôi cần lưu ý là 'thử nghiệm có cho bạn biết điều gì về việc hệ thống có cung cấp giá trị doanh nghiệp không' và 'có phải là thử nghiệm dễ vỡ nếu việc triển khai thay đổi không?' Các thử nghiệm giống như các thử nghiệm được mô tả là hữu ích khi bạn TDDing hệ thống - bạn chưa viết 'lấy đối tượng từ bản ghi cơ sở dữ liệu' vì vậy không thể kiểm tra toàn bộ đơn vị chức năng - nhưng dễ bị thay đổi khi thực hiện loại bỏ chúng một khi hoạt động đầy đủ là có thể kiểm tra.


1

Tinh thần là chính xác.

Lý tưởng nhất, trong một bài kiểm tra đơn vị , bạn đang kiểm tra một đơn vị (một phương thức riêng lẻ hoặc một lớp nhỏ).

Lý tưởng nhất, bạn sẽ khai thác toàn bộ hệ thống cơ sở dữ liệu. Tức là, bạn sẽ chạy phương thức của mình trong môi trường giả mạo và chỉ cần đảm bảo rằng nó gọi đúng API DB theo đúng thứ tự. Bạn rõ ràng, tích cực không muốn kiểm tra DB khi kiểm tra một trong các phương thức của riêng bạn.

Lợi ích rất nhiều. Trên hết, các bài kiểm tra trở nên nhanh chóng vì bạn không cần bận tâm về việc thiết lập môi trường DB chính xác và quay lại sau đó.

Tất nhiên, đây là một mục tiêu cao cả trong bất kỳ dự án phần mềm nào không thực hiện được điều này ngay từ đầu. Nhưng đó là tinh thần của thử nghiệm đơn vị .

Lưu ý rằng có các thử nghiệm khác, như thử nghiệm tính năng, thử nghiệm hành vi, v.v ... khác với phương pháp này - đừng nhầm lẫn giữa "thử nghiệm" với "thử nghiệm đơn vị".


"chỉ cần đảm bảo rằng nó gọi các API DB chính xác theo đúng thứ tự" - vâng, chắc chắn rồi. Cho đến khi bạn nhận ra bạn đã đọc sai tài liệu và thứ tự chính xác thực sự bạn nên sử dụng là hoàn toàn khác nhau. Đừng chế giễu các hệ thống ngoài tầm kiểm soát của bạn.
Joker_vD

4
@Joker_vD Đó là những gì kiểm tra tích hợp dành cho. Trong các thử nghiệm đơn vị, các hệ thống bên ngoài hoàn toàn nên được chế giễu.
Ben Aaronson

1

Có ít nhất một lý do rất quan trọng để không sử dụng quyền truy cập cơ sở dữ liệu trực tiếp trong các thử nghiệm đơn vị của bạn cho mã doanh nghiệp tương tác với cơ sở dữ liệu: nếu bạn thay đổi triển khai cơ sở dữ liệu của mình, bạn sẽ phải viết lại tất cả các thử nghiệm đơn vị đó. Đổi tên một cột, cho mã của bạn, bạn chỉ cần thay đổi một dòng trong định nghĩa trình ánh xạ dữ liệu của bạn. Tuy nhiên, nếu bạn không sử dụng trình ánh xạ dữ liệu của mình trong khi kiểm tra, thì bạn sẽ thấy bạn cũng phải thay đổi mọi bài kiểm tra đơn vị tham chiếu cột này . Điều này có thể biến thành một khối lượng công việc phi thường, đặc biệt là đối với những thay đổi phức tạp hơn mà ít có khả năng tìm kiếm và thay thế.

Ngoài ra, sử dụng trình ánh xạ dữ liệu của bạn như một cơ chế trừu tượng thay vì nói chuyện trực tiếp với cơ sở dữ liệu sẽ giúp loại bỏ hoàn toàn sự phụ thuộc vào cơ sở dữ liệu , điều này có thể không liên quan ngay bây giờ, nhưng khi bạn có tới hàng ngàn bài kiểm tra đơn vị và tất cả chúng đang truy cập cơ sở dữ liệu, bạn sẽ rất biết ơn rằng bạn có thể dễ dàng cấu trúc lại chúng để loại bỏ sự phụ thuộc đó bởi vì bộ kiểm tra của bạn sẽ giảm từ việc mất vài phút để chạy đến mất vài giây, điều này có thể mang lại lợi ích rất lớn cho năng suất của bạn.

Câu hỏi của bạn chỉ ra rằng bạn đang suy nghĩ theo đúng dòng. Như bạn nghi ngờ, bài kiểm tra đơn vị là mã quá. Điều quan trọng là làm cho chúng có thể duy trì và dễ dàng thích ứng với các thay đổi trong tương lai như đối với phần còn lại của cơ sở mã của bạn. Cố gắng để giữ cho chúng có thể đọc được và loại bỏ sự trùng lặp, và bạn sẽ có một bộ thử nghiệm tốt hơn cho nó. Và một bộ kiểm tra tốt là một bộ được sử dụng. Và một bộ kiểm tra được sử dụng sẽ giúp tìm ra lỗi, trong khi một bộ không được sử dụng chỉ là vô dụng.


1

Bài học tốt nhất tôi học được khi học về kiểm thử đơn vị và kiểm thử tích hợp là không kiểm tra các phương pháp, mà kiểm tra các hành vi. Nói cách khác, đối tượng này làm gì?

Khi tôi nhìn theo cách đó, một phương thức lưu giữ dữ liệu và một phương thức khác đọc lại nó bắt đầu có thể kiểm tra được. Tất nhiên, nếu bạn đang kiểm tra các phương thức cụ thể, bạn sẽ kết thúc bằng một thử nghiệm cho từng phương thức, chẳng hạn như:

@Test
public void canSaveData() {
    writeDataToDatabase();
    // what can you assert - the only expectation you can have here is that an exception was not thrown.
}

@Test
public void canReadData() {
    // how do I even get data in there to read if I cannot call the method which writes it?
}

Vấn đề này xảy ra vì quan điểm của các phương pháp thử nghiệm. Đừng thử phương pháp thử. Kiểm tra hành vi. Hành vi của lớp WidgetDao là gì? Nó vẫn tồn tại các vật dụng. Ok, làm thế nào để bạn xác minh nó vẫn tồn tại các vật dụng? Vâng, định nghĩa của sự kiên trì là gì? Nó có nghĩa là khi bạn viết nó, bạn có thể đọc lại. Vì vậy, đọc + viết cùng nhau trở thành một bài kiểm tra, và theo tôi, một bài kiểm tra có ý nghĩa hơn.

@Test
public void widgetsCanBeStored() {
    Widget widget = new Widget();
    widget.setXXX.....
    // blah

    widgetDao.storeWidget(widget);
    Widget stored = widgetDao.getWidget(widget.getWidgetId());
    assertEquals(widget, stored);
}

Đó là một bài kiểm tra logic, gắn kết, đáng tin cậy và theo ý kiến ​​của tôi, có ý nghĩa.

Các câu trả lời khác tập trung vào sự cô lập quan trọng như thế nào, cuộc tranh luận thực tế và thực tế và liệu một bài kiểm tra đơn vị có thể hoặc không thể truy vấn cơ sở dữ liệu. Những người không thực sự trả lời câu hỏi mặc dù.

Để kiểm tra nếu một cái gì đó có thể được lưu trữ, bạn phải lưu trữ nó và sau đó đọc lại. Bạn không thể kiểm tra nếu một cái gì đó được lưu trữ nếu bạn không được phép đọc nó. Đừng kiểm tra việc lưu trữ dữ liệu riêng biệt với việc truy xuất dữ liệu. Bạn sẽ kết thúc với các bài kiểm tra mà không cho bạn biết bất cứ điều gì.


Cách tiếp cận rất sâu sắc, và như bạn nói, tôi nghĩ rằng bạn thực sự đánh vào một trong những nghi ngờ cốt lõi mà tôi có. Cảm ơn!
carlossierra

0

Một ví dụ về trường hợp thất bại mà bạn có thể bắt trước, đó là đối tượng được kiểm tra sử dụng lớp bộ đệm nhưng không duy trì được dữ liệu theo yêu cầu. Sau đó, nếu bạn truy vấn đối tượng, nó sẽ nói "yup, tôi đã có tên và địa chỉ mới", nhưng bạn muốn thử nghiệm thất bại vì nó thực sự không thực hiện đúng như những gì nó được yêu cầu.

Ngoài ra (và xem xét vi phạm trách nhiệm đơn lẻ), giả sử bắt buộc phải duy trì phiên bản chuỗi được mã hóa UTF-8 cho trường theo hướng byte, nhưng thực tế vẫn tồn tại Shift JIS. Một số thành phần khác sẽ đọc cơ sở dữ liệu và hy vọng sẽ thấy UTF-8, do đó yêu cầu. Sau đó, chuyến đi khứ hồi qua đối tượng này sẽ báo cáo tên và địa chỉ chính xác vì nó sẽ chuyển đổi lại từ Shift JIS, nhưng lỗi không được phát hiện bởi bài kiểm tra của bạn. Nó hy vọng sẽ được phát hiện bởi một số thử nghiệm tích hợp sau này, nhưng toàn bộ điểm của các thử nghiệm đơn vị là bắt kịp các vấn đề và biết chính xác thành phần nào chịu trách nhiệm.

Nếu một trong số họ không làm những gì nó được yêu cầu, thì trường hợp thử nghiệm của chính nó sẽ thất bại và chúng tôi có thể sửa nó và chạy lại pin thử nghiệm.

Bạn không thể giả định điều này, bởi vì nếu bạn không cẩn thận, bạn sẽ viết một bộ các bài kiểm tra phụ thuộc lẫn nhau. "Nó có tiết kiệm không?" kiểm tra gọi phương thức lưu là kiểm tra và sau đó là phương thức tải để xác nhận đã lưu. "Nó có tải không?" kiểm tra gọi phương thức lưu để thiết lập lịch thi đấu và sau đó phương thức tải mà nó đang kiểm tra để kiểm tra kết quả. Cả hai thử nghiệm đều dựa vào tính chính xác của phương pháp mà họ không thử nghiệm, nghĩa là cả hai thử nghiệm đều không thực sự kiểm tra tính chính xác của phương pháp mà nó đang thử nghiệm.

Manh mối cho thấy có một vấn đề ở đây, đó là hai bài kiểm tra được cho là đang kiểm tra các đơn vị khác nhau thực sự làm cùng một việc . Cả hai đều gọi một setter theo sau là getter, sau đó kiểm tra kết quả là giá trị ban đầu. Nhưng bạn muốn kiểm tra rằng setter vẫn lưu giữ dữ liệu chứ không phải cặp setter / getter hoạt động cùng nhau. Vì vậy, bạn biết điều gì đó sai, bạn chỉ cần tìm ra những gì và sửa chữa các bài kiểm tra.

Nếu mã của bạn được thiết kế tốt để kiểm tra đơn vị, thì có ít nhất hai cách bạn có thể kiểm tra xem dữ liệu có thực sự được duy trì chính xác theo phương pháp được kiểm tra hay không:

  • mô phỏng giao diện cơ sở dữ liệu và yêu cầu bản ghi giả của bạn thực tế rằng các hàm thích hợp đã được gọi trên đó, với các giá trị dự kiến. Phương pháp này kiểm tra phương thức thực hiện những gì nó được yêu cầu và là thử nghiệm đơn vị cổ điển.

  • vượt qua nó một cơ sở dữ liệu thực tế với cùng một ý định , để ghi lại liệu dữ liệu có được duy trì chính xác hay không. Nhưng thay vì có một chức năng bị chế giễu chỉ nói "yup, tôi đã lấy đúng dữ liệu", bài kiểm tra của bạn sẽ đọc trực tiếp ra khỏi cơ sở dữ liệu và xác nhận nó đúng. Đây có thể không phải là thử nghiệm thuần túy nhất có thể, bởi vì toàn bộ công cụ cơ sở dữ liệu là một thứ khá lớn để sử dụng để viết một bản giả được tôn vinh, với nhiều khả năng tôi nhìn ra một số tinh tế khiến cho bài kiểm tra vượt qua mặc dù có gì đó không đúng (ví dụ như tôi không nên sử dụng cùng một kết nối cơ sở dữ liệu để đọc như đã được sử dụng để viết, bởi vì tôi có thể thấy một giao dịch không được cam kết). Nhưng nó kiểm tra đúng, và ít nhất bạn biết rằng nó chính xác thực hiện toàn bộ giao diện cơ sở dữ liệu mà không phải viết bất kỳ mã giả nào!

Vì vậy, đây chỉ là một chi tiết của việc thực hiện kiểm tra cho dù tôi đọc dữ liệu ra khỏi cơ sở dữ liệu kiểm tra bằng JDBC hay liệu tôi có chế nhạo cơ sở dữ liệu hay không. Dù bằng cách nào đi nữa, tôi có thể kiểm tra đơn vị tốt hơn bằng cách cách ly nó hơn tôi có thể nếu tôi cho phép nó âm mưu với các phương thức không chính xác khác trên cùng một lớp để nhìn đúng ngay cả khi có gì đó không đúng. Do đó, tôi muốn sử dụng bất kỳ phương tiện thuận tiện nào để kiểm tra xem dữ liệu chính xác có còn tồn tại không, ngoài việc tin tưởng vào thành phần mà phương thức tôi đang thử nghiệm.

Nếu mã của bạn không được thiết kế tốt để kiểm tra đơn vị, thì bạn có thể không có lựa chọn nào, bởi vì đối tượng có phương thức bạn muốn kiểm tra có thể không chấp nhận cơ sở dữ liệu dưới dạng phụ thuộc được chèn. Trong trường hợp đó, cuộc thảo luận về cách tốt nhất để cách ly thiết bị được thử nghiệm, sẽ chuyển sang một cuộc thảo luận về mức độ gần gũi để có thể cách ly thiết bị được thử. Kết luận là như nhau, mặc dù. Nếu bạn có thể tránh được âm mưu giữa các đơn vị bị lỗi thì bạn hãy làm theo thời gian có sẵn và bất cứ điều gì khác mà bạn nghĩ về điều đó sẽ hiệu quả hơn trong việc tìm ra lỗi trong mã.


0

Đây là cách tôi thích làm điều đó. Đây chỉ là một lựa chọn cá nhân vì điều này sẽ không ảnh hưởng đến kết quả của sản phẩm, chỉ là cách sản xuất nó.

Điều này phụ thuộc vào possibilites để có thể thêm các giá trị giả trong cơ sở dữ liệu của bạn mà không cần ứng dụng bạn đang kiểm tra.

Giả sử bạn có hai bài kiểm tra: A - đọc cơ sở dữ liệu B - chèn vào cơ sở dữ liệu (phụ thuộc vào A)

Nếu A vượt qua, thì bạn chắc chắn rằng kết quả của B sẽ phụ thuộc vào phần được kiểm tra trong B chứ không phải phụ thuộc. Nếu A thất bại, bạn có thể có âm tính giả cho B. Lỗi có thể là B hoặc A. Bạn không thể biết chắc chắn cho đến khi A trả lại thành công.

Tôi sẽ không thử viết một số truy vấn trong kiểm tra đơn vị vì bạn không thể biết cấu trúc DB đằng sau ứng dụng (hoặc nó có thể thay đổi). Có nghĩa là trường hợp thử nghiệm của bạn có thể thất bại vì chính mã của bạn. Trừ khi bạn viết bài kiểm tra cho bài kiểm tra, nhưng ai sẽ kiểm tra bài kiểm tra ...


-1

Cuối cùng, nó thuộc về những gì bạn muốn kiểm tra.

Đôi khi nó là đủ để kiểm tra giao diện được cung cấp của lớp của bạn (ví dụ: bản ghi được tạo và lưu trữ và có thể được truy xuất sau đó, có thể sau khi "khởi động lại"). Trong trường hợp này, tốt (và thường là một ý tưởng tốt) để sử dụng các phương pháp được cung cấp để thử nghiệm. Điều này cho phép các bài kiểm tra được sử dụng lại, ví dụ nếu bạn muốn thay đổi cơ chế lưu trữ (cơ sở dữ liệu khác nhau, cơ sở dữ liệu trong bộ nhớ để kiểm tra, ...).

Lưu ý rằng điều này có nghĩa là bạn chỉ thực sự quan tâm rằng lớp đang tuân thủ hợp đồng của nó (tạo, lưu trữ và truy xuất các bản ghi trong trường hợp này), chứ không phải làm thế nào nó đạt được điều này. Nếu bạn tạo các bài kiểm tra đơn vị của mình một cách thông minh (đối với một giao diện, không phải một lớp trực tiếp), bạn có thể kiểm tra các triển khai khác nhau, vì chúng cũng phải tuân thủ hợp đồng của giao diện.

Mặt khác, trong một số trường hợp, bạn phải thực sự xác minh xem công cụ được duy trì như thế nào (có thể một số quy trình khác phụ thuộc vào dữ liệu ở định dạng đúng trong cơ sở dữ liệu đó?). Bây giờ bạn không thể chỉ dựa vào việc lấy lại bản ghi chính xác từ lớp, thay vào đó bạn phải xác minh rằng nó được lưu trữ chính xác trong cơ sở dữ liệu. Và cách trực tiếp nhất để làm điều đó là truy vấn cơ sở dữ liệu.

Bây giờ bạn không chỉ quan tâm đến lớp tuân thủ hợp đồng của nó (tạo, lưu trữ và truy xuất), mà còn là cách nó đạt được điều này (vì dữ liệu vẫn tồn tại cần phải tuân thủ giao diện khác). Tuy nhiên, bây giờ các bài kiểm tra phụ thuộc vào cả giao diện lớp định dạng lưu trữ, do đó sẽ khó sử dụng lại chúng đầy đủ. (Một số người có thể gọi các loại thử nghiệm này là "thử nghiệm tích hợp".)


@downvoters: bạn có thể cho tôi biết lý do của bạn để tôi có thể cải thiện các khía cạnh mà bạn nghĩ rằng câu trả lời của tôi còn thiếu không?
hoffmale
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.