2016-03-29 14 views
6

Hãy tưởng tượng tôi có phương pháp sau đây cần được kiểm tra:Làm thế nào để tránh Thread.sleep trong bài kiểm tra đơn vị?

@Autowired 
private RoutingService routingservice; 

public void methodToBeTested() { 
    Object objectToRoute = initializeObjectToRoute(); 
    if (someConditions) { 
     routingService.routeInOneWay(objectToRoute); 
    } else { 
     routingService.routeInAnotherWay(objectToRoute); 
    } 
} 

Trong trường hợp này RoutingService đang chạy trong thread riêng biệt, do đó trong constructor của nó, chúng tôi đã điều sau đây:

Thread thread = new Thread(this); 
thread.setDaemon(true); 
thread.start(); 

Vấn đề là RoutingService thay đổi trạng thái của objectToRoute và đây chính xác là những gì tôi muốn kiểm tra, nhưng điều này không xảy ra ngay lập tức, do đó thử nghiệm không thành công. Tuy nhiên, nếu tôi thêm Thread.sleep() thì nó hoạt động, nhưng đây là thực hành không tốt như tôi biết.

Làm cách nào để tránh Thread.sleep() trong trường hợp này?

+0

Sử dụng 'Thread.sleep' trong một bài kiểm tra đơn vị không phải là thực hành không tốt, vì tất cả những gì bạn đang làm là bắt chước thời gian, cần thiết cho một số bài kiểm tra đơn vị. Lý do mọi người nói rằng bằng cách sử dụng 'Thread.sleep' là một thực tế tồi tệ là bởi vì nó đôi khi được sử dụng như một nỗ lực để sửa chữa điều kiện chủng tộc. Bạn chỉ sử dụng 'Thread.sleep' trong các bài kiểm tra, hoặc trong mã nguồn của bạn? –

+0

Khi bạn đang thử nghiệm mã chuỗi, làm thế nào bạn sẽ đảm bảo kiểm tra đơn vị của bạn không flaky? Rằng họ luôn luôn thực hiện một cách xác định. Tôi nghĩ việc chế nhạo lớp Service là một opiton tốt hơn –

+0

Tôi đang sử dụng giấc ngủ chỉ trong các bài kiểm tra, nhưng tìm thấy khá một vài nơi mà mọi người đề cập đến mà thường ngủ không phải là tốt trong các bài kiểm tra đơn vị.Ví dụ, plugin SonarLint đang phàn nàn và nói rằng nó vi phạm và đưa ra mô tả sau: "Sử dụng Thread.sleep trong một thử nghiệm chỉ là một ý tưởng tồi. Nó tạo ra các kiểm tra giòn có thể thất bại không thể đoán trước tùy thuộc vào môi trường (" máy của tôi! ") hoặc tải." – Rufi

Trả lời

4

Nếu bạn đang thử nghiệm methodToBeTested, bạn chỉ cần giả lập routingservice. Bạn không nên thử nghiệm bất kỳ phương thức nào mà các cuộc gọi methodToBeTested. Tuy nhiên, có vẻ như bạn muốn kiểm tra RoutingService (bạn đã nói "Vấn đề là RoutingService thay đổi trạng thái của objectToRoute và đây chính xác là những gì tôi muốn kiểm tra"). Để kiểm tra các phương pháp RoutingService, bạn nên viết các bài kiểm tra đơn vị riêng biệt cho các phương pháp đó.

+0

Vâng, điều này có thể là một cách, tuy nhiên, tôi không thể nói rằng tôi thích nó. Hầu hết các thử nghiệm của tôi có thể di chuyển từ bài kiểm tra đơn vị để kiểm tra tích hợp sau đó. RoutingService được kiểm tra, nhưng trong trường hợp này tôi muốn xác minh rằng trong một số điều kiện nhất định định tuyến đã được thực hiện, tuy nhiên, nó có thể mất một thời gian. Tất nhiên, tôi có thể giả định RoutingService và xác minh rằng phương thức cụ thể đã được gọi, nhưng sau đó tôi sẽ không bao gồm sự thay đổi trạng thái. – Rufi

+0

Có, tôi sẽ nói nếu bạn muốn làm điều này, nó sẽ trở thành một thử nghiệm tích hợp, và không nên chạy với bộ kiểm tra đơn vị bình thường. các bài kiểm tra đơn vị phải hoàn thành nhanh chóng và nhất quán, vì vậy các nhà phát triển có thể chạy tất cả trước khi kiểm tra trong bất kỳ mã nào. Có một bộ kiểm tra tích hợp riêng biệt chạy thường xuyên (chẳng hạn như qua Jenkins) – forgivenson

0

Bạn có thể giả lập objectToRoute để đặt giá trị CompletableFuture và sau đó gọi get về điều đó trong xác nhận của bạn. Điều này sẽ đợi cho đến khi giá trị được đặt trước khi tiếp tục. Sau đó đặt thời gian chờ @Test(timeout=5000) trong trường hợp giá trị không bao giờ được đặt.

Điều này có lợi thế là thử nghiệm sẽ không chờ lâu hơn mức cần thiết và khó thực hiện hơn do thời gian quá ngắn vì bạn có thể làm cho thời gian chờ lớn hơn nhiều so với bình thường.

0

Điều đó tùy thuộc. Như Ben Green nói trong bình luận của mình, giấc ngủ là nguy hiểm trong các bài kiểm tra vì nó có thể che giấu một điều kiện chủng tộc. Bạn biết nếu thiết kế tổng thể chứa điều kiện chủng tộc như vậy, nơi dịch vụ có thể được sử dụng trước khi tuyến đường sẵn sàng. Nó có, bạn nên sửa chữa nó trong mã, ví dụ bằng cách kiểm tra một điều kiện sẵn sàng và kiểm tra nó giống nhau trong lớp thử nghiệm của bạn.

Nếu bạn biết rằng nó không thể xảy ra, bạn nên ghi lại nó trong mã chính của bạn trong lớp thử nghiệm của bạn. Đó sẽ là một sự biện minh hoàn hảo cho một giấc ngủ.

(Tôi cho rằng đây là một thử nghiệm tích hợp - cho unit tests chế giễu nên đủ như bạn đã nói trong câu trả lời khác)

0

Thay vì tránh Thread.sleep(), Bạn có thể vượt qua giá trị như không trong trường hợp thử nghiệm Junit.

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