2010-08-03 27 views
11

Tôi phải kiểm tra một phương pháp thực hiện một số lượng công việc nhất định sau một khoảng thời gian.Thử nghiệm đơn vị C# - Thread.Sleep (x) - Làm thế nào để giả lập đồng hồ hệ thống

Khoảng thời gian được chuyển thành tham số cho lớp để tôi chỉ có thể vượt qua 0 hoặc 1 nhưng tôi quan tâm đến cách chế độ đồng hồ hệ thống nếu trường hợp này không xảy ra.

Trong thử nghiệm của tôi, tôi muốn có thể chỉ đơn giản là thiết lập thời gian chuyển tiếp bởi TimeSpan Khoảng thời gian và có chủ đề thức dậy.

Tôi chưa bao giờ viết kiểm tra mã hoạt động theo chuỗi thực thi trước đây và tôi chắc chắn có một số cạm bẫy cần tránh - vui lòng giải thích cách tiếp cận bạn sử dụng.

Cảm ơn!

+0

Thực sự thay đổi giá trị của đồng hồ (mà tôi chắc chắn bạn không muốn làm), bạn sẽ không có thể nhận được kết quả bạn đang tìm kiếm. –

+2

Giải pháp ưu tiên là cách ly chức năng định thời với một dịch vụ để bạn có thể thử dịch vụ cho các bài kiểm tra của mình. Nếu bạn không thể làm điều này (thường vì nó là một codebase hiện có), thì một cách khác là sử dụng một khung như Moles để hủy bỏ các cuộc gọi tĩnh: http://research.microsoft.com/en-us/projects/moles/ –

Trả lời

15

Nếu bạn không muốn kiểm tra thực tế là các sợi thực sự ngủ, một cách tiếp cận đơn giản hơn (và một trong đó là có thể) là có một ISleepService. Sau đó bạn có thể giả lập điều này, và sau đó không ngủ trong các thử nghiệm của bạn, nhưng có một thực hiện mà gây ra một Thread.Sleep trong mã sản xuất của bạn.

ISleepService sleepService = Container.Resolve<ISleepService>(); 

.. 

while (running) 
{ 
    ... 
    // Work 
    ... 
    sleepService.Sleep(Interval); 
} 

Ví dụ sử dụng Moq:

public interface ISleepService 
    { 
     void Sleep(int interval); 
    } 

    [Test] 
    public void Test() 
    { 
     const int Interval = 1000; 

     Mock<ISleepService> sleepService = new Mock<ISleepService>(); 
     sleepService.Setup(s => s.Sleep(It.IsAny<int>())); 
     _container.RegisterInstance(sleepService.Object); 

     SomeClass someClass = _container.Resolve<SomeClass>(); 
     someClass.DoSomething(interval: Interval); 

     //Do some asserting. 

     //Optionally assert that sleep service was called 
     sleepService.Verify(s => s.Sleep(Interval)); 
    } 

    private class SomeClass 
    { 
     private readonly ISleepService _sleepService; 

     public SomeClass(IUnityContainer container) 
     { 
      _sleepService = container.Resolve<ISleepService>(); 
     } 

     public void DoSomething(int interval) 
     { 
      while (true) 
      { 
       _sleepService.Sleep(interval); 
       break; 
      } 
     } 
    } 

Cập nhật

Trên một thiết kế \ bảo trì lưu ý, nếu nó là đau đớn để thay đổi các nhà xây dựng của "SomeClass", hoặc để thêm Dependency Injection trỏ đến người dùng của lớp, sau đó mẫu kiểu trình định vị dịch vụ có thể trợ giúp tại đây, ví dụ:

private class SomeClass 
{ 
    private readonly ISleepService _sleepService; 

    public SomeClass() 
    { 
     _sleepService = ServiceLocator.Container.Resolve<ISleepService>(); 
    } 

    public void DoSomething(int interval) 
    { 
     while (true) 
     { 
      _sleepService.Sleep(interval); 
      break; 
     } 
    } 
} 
+0

Tuyệt vời - điều này làm cho rất nhiều ý nghĩa - Moq đã chắc chắn trên bản đồ đường quá vì vậy bạn trả lời đã cung cấp một khởi đầu dễ dàng. – gav

2

Bạn thực sự không thể giả lập đồng hồ hệ thống.

Nếu bạn cần thay đổi hành vi tạm dừng của mã như thế này, bạn sẽ cần phải cấu trúc lại nó để bạn không gọi trực tiếp số Thread.Sleep().

Tôi sẽ tạo một dịch vụ đơn lẻ, có thể được đưa vào ứng dụng khi nó được kiểm tra. Dịch vụ Singleton sẽ phải bao gồm các phương thức để cho phép một số người gọi bên ngoài (như kiểm thử đơn vị) có thể hủy bỏ hoạt động của giấc ngủ. Bạn có thể sử dụng phương thức của đối tượng có tham số thời gian chờ. Bằng cách này, bạn có thể kích hoạt mutex để hủy "ngủ" hoặc để cho nó hết thời gian chờ:

public WaitHandle CancellableSleep = new WaitHandle(); // publicly available 

// in your code under test use this instead of Thread.Sleep()... 
while(running) { 
    // .. work .. 
    CancellableSleep.WaitOne(Interval); // suspends thread for Interval timeout 
} 


// external code can cancel the sleep by doing: 
CancellableSleep.Set(); // trigger the handle... 
+1

WaitHandle là một cách rất nặng (về mặt tài nguyên hệ thống và hiệu suất) để cung cấp một thay thế cho 'Thread.Sleep()'.Tôi sẽ không khuyên bạn nên một WaitHandle trừ khi bạn có mã khác có thể cung cấp hướng dẫn như khi chủ đề nên thức dậy. –

+1

+1 vì không thể giả lập đồng hồ hệ thống. – Larsenal

+1

Thực ra bạn có thể sử dụng chặn cuộc gọi hệ thống, nhưng điều đó chắc chắn sẽ là quá mức cần thiết. –

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