Tách đơn vị kiểm tra theo yêu cầu hoặc phương pháp


16

Đầu tiên, xin lỗi cho tiêu đề, tôi không thể nghĩ ra cách dễ nhất để giải thích nó!

Tôi có một phương pháp mà tôi muốn viết bài kiểm tra đơn vị cho. Tôi sẽ giữ nó khá chung chung vì tôi không muốn thảo luận về việc thực hiện phương pháp, chỉ là thử nghiệm phương pháp này. Phương pháp là:

public void HandleItem(item a)
{         
     CreateNewItem();
     UpdateStatusOnPreviousItem();
     SetNextRunDate();
}

Vì vậy, lớp này có một phương thức công khai sau đó gọi một số phương thức riêng để thực hiện logic.

Vì vậy, khi viết bài kiểm tra đơn vị tôi muốn kiểm tra cả ba điều đã được thực hiện. Vì tất cả chúng đều được gọi trong cùng một lần chạy, tôi nghĩ rằng tôi có thể làm điều đó như một bài kiểm tra:

public void GivenItem_WhenRun_Thenxxxxx
{
     HandleItem(item);
     // Assert item has been created
     // Assert status has been set on the previous item
     // Assert run date has been set
}

Nhưng tôi nghĩ tôi cũng có thể viết nó thành ba bài kiểm tra riêng biệt:

public void GivenItem_WhenRun_ThenItemIsCreated()
{
    HandleItem(item);
}

public void GivenItem_WhenRun_ThenStatusIsUpdatedOnPreviousItem()
{
   HandleItem(item);
}

public void GivenItem_WhenRun_ThenRunDateIsSet()
{
     HandleItem(item);
}

Vì vậy, với tôi điều này có vẻ đẹp hơn vì về cơ bản nó là các yêu cầu liệt kê, nhưng sau đó cả ba đều có liên quan và yêu cầu chính xác cùng một công việc được thực hiện trên phương thức được thử nghiệm, vì vậy tôi đang chạy cùng một mã 3 lần.

Có một cách tiếp cận được đề nghị để thực hiện với điều này?

Cảm ơn

Câu trả lời:


29

Có một sự khác biệt tinh tế giữa cả hai phương pháp. Trong trường hợp đầu tiên, khi lần đầu tiên Assertthất bại, hai người kia không chạy nữa. Trong trường hợp thứ hai, cả ba bài kiểm tra luôn được chạy, ngay cả khi một lần thất bại. Tùy thuộc vào bản chất của chức năng được kiểm tra, điều này có thể phù hợp hoặc không phù hợp với trường hợp của bạn:

  • Nếu có ý nghĩa để chạy ba xác nhận độc lập với một xác nhận khác, bởi vì khi một lần thất bại, hai lần khác có thể vẫn không thất bại, thì cách tiếp cận thứ hai có lợi thế là bạn có được kết quả kiểm tra đầy đủ cho cả 3 lần kiểm tra trong một lần chạy. Điều này có thể có lợi nếu bạn có thời gian xây dựng đáng chú ý, vì nó cho bạn cơ hội sửa tối đa 3 lỗi cùng một lúc trước khi thực hiện bản dựng tiếp theo.

  • tuy nhiên, nếu thất bại của thử nghiệm đầu tiên sẽ luôn ám chỉ hai thử nghiệm còn lại cũng sẽ thất bại, thì có lẽ tốt hơn là sử dụng phương pháp đầu tiên (vì sẽ không có ý nghĩa gì khi chạy thử nghiệm nếu bạn đã biết trước nó sẽ Thất bại).


2
+1, điểm tốt. Nó đã không xảy ra với tôi rằng thời gian xây dựng cũng có thể là một nút cổ chai.
Kilian Foth

1
@KilianFoth: Bạn không thường xuyên làm việc trong C ++ :(
Matthieu M.

1
@MatthieuM.: Để công bằng, câu hỏi được gắn thẻ "C #"
Doc Brown

10

Câu trả lời ngắn: Điều quan trọng hơn nhiều các bài kiểm tra của bạn bao gồm tất cả các chức năng so với cách chúng thực hiện.

Câu trả lời dài hơn: Nếu bạn vẫn muốn chọn trong số các giải pháp tương đương lớn này, bạn có thể sử dụng các tiêu chí phụ trợ cho những gì tốt nhất. Ví dụ,

  • dễ đọc: nếu phương thức thực hiện nhiều thứ không liên quan chặt chẽ, một bài kiểm tra kết hợp có thể khó hiểu. Tuy nhiên, bản thân phương thức cũng có thể khó hiểu, vì vậy có lẽ bạn nên cấu trúc lại phương thức chứ không phải kiểm tra!)
  • hiệu quả: nếu thực hiện phương pháp mất nhiều thời gian, đó có thể là một lý do yếu để kết hợp cả ba kiểm tra để tiết kiệm thời gian
  • hiệu quả2: nếu việc chạy mã thiết lập của khung công tác của bạn mất nhiều thời gian, đó cũng có thể là một lý do yếu để tránh nhiều phương pháp thử nghiệm. (Tuy nhiên, nếu đây thực sự là một vấn đề, có lẽ yuo nên sửa chữa hoặc thay đổi thiết lập thử nghiệm của bạn - kiểm tra hồi quy sẽ mất nhiều giá trị của chúng nếu bạn không thể chạy nhanh như chớp.)

2

Sử dụng một cuộc gọi phương thức với nhiều khẳng định. Đây là lý do tại sao:

Khi bạn kiểm tra HandleItem (a), bạn đang kiểm tra rằng phương thức đã đưa mục vào trạng thái chính xác. Thay vì "một khẳng định cho mỗi thử nghiệm", hãy nghĩ "một khái niệm logic cho mỗi thử nghiệm".

Câu hỏi: Nếu một CreatNewItem không thành công, nhưng hai phương thức còn lại thành công, điều này có nghĩa là HandItem đã hoàn thành thành công? Tôi đoán là không.

Với nhiều xác nhận (với các thông điệp phù hợp) bạn sẽ biết chính xác những gì đã thất bại. Bạn thường kiểm tra một phương thức nhiều lần cho nhiều đầu vào hoặc trạng thái đầu vào, không để tránh nhiều xác nhận.

IMO, những câu hỏi này thường là một dấu hiệu của một cái gì đó khác. Đó là một dấu hiệu cho thấy HandItem không thực sự là thứ bạn có thể "kiểm tra đơn vị" vì dường như nó chỉ ủy thác cho các phương thức khác. Khi bạn chỉ đơn giản xác nhận rằng HandItem gọi các phương thức khác một cách chính xác, nó sẽ trở thành một ứng cử viên kiểm tra tích hợp (trong trường hợp đó bạn vẫn có 3 xác nhận).

Bạn có thể muốn xem xét công khai 3 phương thức khác và kiểm tra chúng một cách độc lập. Hoặc thậm chí trích xuất chúng sang một lớp khác.


0

Sử dụng phương pháp thứ 2. Với cách tiếp cận thứ 1 của bạn, nếu thử nghiệm thất bại, bạn sẽ không biết tại sao ngay lập tức, bởi vì đó có thể là một trong 3 chức năng thất bại. Với cách tiếp cận thứ hai, bạn sẽ biết ngay nơi xảy ra sự cố. Bạn có thể đặt mã trùng lặp bên trong chức năng Cài đặt thử nghiệm.


-1

IMHO bạn nên kiểm tra riêng ba phần của phương pháp này để bạn biết cụ thể hơn về những điều đang xảy ra khi chúng xảy ra trong khi tránh đi qua cùng một phần mã của bạn hai lần.


-2

Tôi không nghĩ rằng có một trường hợp mạnh mẽ để viết các phương pháp kiểm tra riêng cho trường hợp sử dụng của bạn. Nếu bạn muốn nhận kết quả từ cả ba điều kiện khác nhau, bạn có thể kiểm tra cả ba và in các lỗi của chúng bằng cách nối chúng trong một stringvà xác nhận xem chuỗi có còn trống không khi bạn hoàn thành bài kiểm tra. Bằng cách giữ tất cả chúng trong cùng một phương thức, các điều kiện và thông báo lỗi của bạn ghi lại điều kiện hậu kỳ dự kiến ​​của phương thức ở một nơi, thay vì chia nó thành ba phương thức có thể được tách ra sau đó.

Điều này không có nghĩa là thử nghiệm đơn của bạn sẽ có nhiều mã hơn, nhưng nếu bạn có quá nhiều điều kiện hậu kỳ đó là một vấn đề, có lẽ bạn muốn cấu trúc lại các phương thức thử nghiệm của mình để kiểm tra các phương thức riêng lẻ bên trong HandleItem.

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.