2009-12-08 39 views
8

Các phương pháp được đề xuất để sử dụng Thread.sleep() để tăng tốc các thử nghiệm là gì.Thử nghiệm với Thread.sleep

Tôi đang thử nghiệm thư viện mạng có chức năng thử lại khi kết nối bị ngắt hoặc lỗi hết thời gian chờ, vv Tuy nhiên, thư viện sử dụng Thread.sleep() giữa lần thử lại (vì vậy nó sẽ không kết nối hàng nghìn lần trong khi máy chủ khởi động lại) . Cuộc gọi đang làm chậm các bài kiểm tra đơn vị một cách đáng kể, và tôi tự hỏi các tùy chọn là gì để ghi đè lên nó.

Lưu ý, tôi mở để thực sự thay đổi mã hoặc sử dụng khuôn khổ giả mạo để tạo Thread.sleep(), nhưng muốn nghe ý kiến ​​/ đề xuất của bạn trước tiên.

+0

này có thể được xem như một casestudy cho thử nghiệm đơn vị với mocking – dfa

+0

Không sử dụng Thread.sleep(), sử dụng một phương thức wait(). Thread.sleep() sử dụng các chu kỳ CPU, trong khi wait() thì không. – dhiller

Trả lời

11

Nó thường là một ý tưởng tốt để giao chức năng thời gian liên quan đến một thành phần riêng biệt. Điều đó bao gồm nhận được thời gian hiện tại, cũng như sự chậm trễ như Thread.sleep(). Bằng cách này, bạn có thể dễ dàng thay thế thành phần này bằng cách thử nghiệm, cũng như chuyển sang thực hiện khác.

+1

Tôi đã bị cám dỗ để tạo ra một lớp 'Máy' để tóm tắt tất cả điều đó. – notnoop

+0

Con đường để đi. Bằng cách này bạn cũng có thể thiết lập cấu hình của bạn hoặc thậm chí bỏ qua bất cứ điều gì bạn muốn chỉ ở một nơi, thay vì sau đó lan truyền logic này máng mã. –

+0

@notnoop Chính xác những gì tôi đã làm với một lớp 'Đồng hồ'. Hỗ trợ các hoạt động cơ bản như 'Clock.now()', 'Clock.freeze()', 'Clock.freeze (pointInTime)' và cứ thế. Không có thành phần nào tương tác trực tiếp với thời gian chạy để tìm nạp thời gian mà thay vào đó là đi qua 'Đồng hồ'. –

3

Đặt thời gian ngủ có thể định cấu hình thông qua trình cài đặt và cung cấp giá trị mặc định. Vì vậy, trong các bài kiểm tra đơn vị của bạn, gọi setter với một đối số nhỏ (1 ví dụ), và sau đó thực hiện các phương pháp mà sẽ gọi Thread.sleep().

Một cách tiếp cận tương tự khác là thực hiện nếu có thể định cấu hình qua boolean, do đó Thread.sleep() hoàn toàn không được gọi nếu boolean được đặt thành false.

2

Tạo một số loại trì hoãn thử lại đại diện cho chính sách để thử lại sự chậm trễ. Gọi một số phương thức trên loại chính sách cho sự chậm trễ. Mock nó như bạn muốn. Không có logic điều kiện hoặc true/false cờ. Chỉ cần tiêm loại mà bạn muốn.

Trong ConnectRetryPolicy.java

public interface ConnectRetryPolicy { 
    void doRetryDelay(); 
} 

Trong SleepConnectRetryPolicy.java

public class final SleepConnectRetryPolicy implements ConnectRetryPolicy { 
    private final int delay; 
    public SleepConnectRetryPolicy(final int delay) { 
     this.delay = delay; 
    } 

    @Override 
    public void doRetryDelay() { 
     try { 
      Thread.sleep(delay); 
     } catch (InterruptedException ie) { 
      log.error("connection delay sleep interrupted", ie); 
     } 
    } 
} 

Trong MockConnectRetryPolicy.java

public final class MockConnectRetryPolicy implements ConnectRetryPolicy {  
    @Override 
    public void doRetryDelay() { 
     // no delay 
    } 
} 
+0

Đây không chỉ là một chính sách, mà là một người thực thi giấc ngủ có thể cấu hình được. Một chính sách sẽ chỉ đại diện cho chiến lược xung quanh việc ngủ, không thực thi nó. Đối với phần còn lại, ý tưởng âm thanh. –

1

Eugene là đúng, làm cho thành phần của riêng bạn để quấn hệ thống đó là ngoài tầm kiểm soát của bạn Chỉ cần làm điều này bản thân mình nghĩ rằng tôi muốn chia sẻ, điều này được gọi là 'SelfShunt' kiểm tra này:

Generator là một khi bạn gọi getId(), nó sẽ trả về thời gian hiện tại của hệ thống.

public class GeneratorTests implements SystemTime { 

    private Generator cut; 
    private long currentSystemTime; 

    @Before 
    public void setup(){ 
     cut = Generator.getInstance(this); 
    } 

    @Test 
    public void testGetId_returnedUniqueId(){ 
     currentSystemTime = 123; 

     String id = cut.getId(); 

     assertTrue(id.equals("123")); 
    } 

    @Override 
    public long currentTimeMillis() { 
     return currentSystemTime; 
    } 
} 

Chúng tôi thực hiện lớp thử nghiệm 'SelfShunt' và trở thành thành phần SystemTime theo cách chúng tôi có toàn quyền kiểm soát thời gian.

public class BlundellSystemTime implements SystemTime { 

    @Override 
    public long currentTimeMillis(){ 
     return System.currentTimeMillis(); 
    } 
} 

Chúng tôi quấn thành phần không nằm trong tầm kiểm soát của mình.

public interface SystemTime { 

    long currentTimeMillis(); 

} 

Sau đó thực hiện một giao diện để thử nghiệm của chúng tôi có thể 'SelfShunt'

1

tôi sẽ tranh luận tại sao bạn cố gắng thử nghiệm Thread.sleep. Có vẻ như tôi đang cố gắng kiểm tra hành vi này như một hệ quả của một số sự kiện.

tức lànhững gì sẽ xảy ra nếu:

  • thời gian chờ kết nối
  • kết nối giảm

Nếu bạn mã mô hình dựa trên các sự kiện sau đó bạn có thể kiểm tra những gì nên xảy ra nên một sự kiện đặc biệt xảy ra thay vì phải đưa ra một xây dựng mặt nạ đó cho các cuộc gọi API đồng thời. Khác bạn đang thực sự thử nghiệm là gì? Bạn đang thử nghiệm cách ứng dụng của bạn phản ứng với các kích thích khác nhau hay đơn giản là kiểm tra JVM đang hoạt động chính xác?

Tôi đồng ý với các độc giả khác đôi khi hữu ích khi đặt trừu tượng xung quanh bất kỳ thời gian mã hoặc chuỗi nào liên quan tức là đồng hồ ảo http://c2.com/cgi/wiki?VirtualClock để bạn có thể thử bất kỳ hành vi thời gian/đồng thời nào và tập trung vào hành vi của đơn vị. Nó cũng có vẻ như bạn nên áp dụng một mô hình nhà nước để bạn phản đối có hành vi cụ thể tùy thuộc vào trạng thái của nó trong đó, tức là AwaitingConnectionState, ConnectionDroppedState. Chuyển đổi sang các trạng thái khác nhau, tức là hết thời gian chờ, ngắt kết nối v.v. Không chắc chắn nếu điều này vượt quá nhu cầu của bạn nhưng chắc chắn sẽ loại bỏ rất nhiều logic điều kiện có thể làm cho mã phức tạp hơn và không rõ ràng.

Nếu bạn tiếp cận theo cách này, bạn vẫn có thể kiểm tra hành vi ở cấp đơn vị trong khi vẫn thử nghiệm tại chỗ với kiểm tra tích hợp hoặc kiểm tra chấp nhận sau này.

2

Tôi chỉ phải đối mặt với một vấn đề tương tự và tôi đã tạo ra một giao diện Sleeper để trừu tượng này đi:

public interface Sleeper 
{ 
    void sleep(long millis) throws InterruptedException; 
} 

Việc thực hiện mặc định sử dụng Thread.sleep():

public class ThreadSleeper implements Sleeper 
{ 
    @Override 
    public void sleep(long millis) throws InterruptedException 
    { 
     Thread.sleep(millis); 
    } 
} 

Trong các thử nghiệm đơn vị của tôi, tôi tiêm một FixedDateTimeAdvanceSleeper :

public class FixedDateTimeAdvanceSleeper implements Sleeper 
{ 
    @Override 
    public void sleep(long millis) throws InterruptedException 
    { 
     DateTimeUtils.setCurrentMillisFixed(DateTime.now().getMillis() + millis); 
    } 
} 

Điều này cho phép tôi o truy vấn thời gian trong một thử nghiệm đơn vị:

assertThat(new DateTime(DateTimeUtils.currentTimeMillis())).isEqualTo(new DateTime("2014-03-27T00:00:30")); 

Lưu ý rằng bạn cần phải sửa chữa lần đầu tiên sử dụng DateTimeUtils.setCurrentMillisFixed(new DateTime("2014-03-26T09:37:13").getMillis()); lúc bắt đầu thử nghiệm của bạn và khôi phục thời gian một lần nữa sau khi thử nghiệm sử dụng DateTimeUtils.setCurrentMillisSystem();

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