2010-10-01 47 views
7

Tôi có một ứng dụng Silverlight điển hình với dịch vụ WCF và tôi đang sử dụng slsvcutil.exe để tạo proxy máy khách chuẩn để giao tiếp với dịch vụ web. Tôi đang cố gắng để viết bài kiểm tra đơn vị và tôi đang cố gắng sử dụng khung kiểm tra đơn vị Silverlight và Moq để giả mạo proxy và loại bỏ sự phụ thuộc dịch vụ để thử nghiệm.Gọi các cuộc gọi không đồng bộ trong Silverlight WCF Proxy bằng cách sử dụng Moq

Tôi rất mới đối với Moq và gặp rất nhiều sự cố khi tự động tăng các sự kiện hoàn thành trên proxy giả tự động khi cuộc gọi dịch vụ được thực hiện để mô phỏng các cuộc gọi không đồng bộ.

Để làm cho proxy "mockable" Tôi đã tạo ra giao diện đơn giản của riêng mình cho các cuộc gọi proxy tạo ra và các sự kiện hoàn thành của họ:

public interface IServiceProxy 
{ 
    void TestAsync(TestRequest request); 
    void TestAsync(TestRequest request, object userState); 
    event EventHandler<TestCompletedEventArgs> TestCompleted; 
} 

Tôi cũng subclassed đối tượng proxy được tạo ra để thực hiện giao diện:

public class MyServiceProxy : GeneratedServiceClient, IServiceProxy, ICommunicationObject 
{ 
    // ... overloaded proxy constructors 
} 

Sau khi xem xét các tài liệu Moq, đây là cách tôi đang cố gắng để thiết lập các mô hình để dự đoán() gọi TestAsync và ngay lập tức nâng cao sự kiện TestCompleted với kết quả trong EventArgs:

[TestMethod] 
public void Test_Returns_Expected() 
{ 
    var mockProxy = new Mock<IServiceProxy>(); 
    var result = new TestResponse() { Value = true }; 

    this.mockProxy.Setup(
     p => p.TestAsync(It.IsAny<TestRequest>())) 
     .Raises(p => p.TestCompleted += null, new TestCompletedEventArgs(new object[] { result }, null, false, null)); 

    // rest of the test to actually use the mock and assert things 
} 

Mọi thứ đều tốt, nhưng khi tôi cố gắng chạy bất kỳ loại thử nghiệm nào bằng cách sử dụng giả lập và đặt điểm ngắt, sự kiện TestCompleted sẽ không bao giờ được nâng lên khi tôi gọi TestAsync().

Có bất kỳ điều gì rõ ràng rằng tôi bị thiếu hoặc có bất kỳ ý tưởng nào tốt hơn về chế nhạo các loại proxy dịch vụ không đồng bộ này trong Silverlight không?

Cảm ơn!

EDIT:

Để được rõ ràng hơn những gì tôi đang thực sự cố gắng để thử nghiệm là một lớp helper tôi đã thực hiện trong đó có một thể hiện của IServiceProxy và cung cấp một giao diện dịch vụ làm sạch cho ViewModel của tôi để sử dụng bằng cách chấp nhận Action<TResponse, Exception> callback tham số thay vì xử lý các sự kiện gọi lại trong ViewModel của tôi. Tôi hiểu làm thế nào tôi có thể thử này cũng như để trực tiếp kiểm tra ViewModel của tôi, nhưng tôi figured nó sẽ là tốt đẹp để kiểm tra lớp helper của chính nó đầu tiên.

Dưới đây là một ví dụ về những gì tôi đang nói về:

public class HelperClient : IServiceHelper 
{ 
    private IServiceProxy proxy; 

    public HelperClient(IServiceProxy proxy) 
    { 
     this.proxy = proxy; 

     // register to handle all async callback events 
     this.proxy.TestCompleted += new EventHandler<TestCompletedEventArgs>(TestCompleted); 
    } 

    public void Test(TestRequest request, Action<TestResponse, Exception> response) 
    { 
     this.proxy.TestAsync(request, response); 
    } 

    private void TestCompleted(object sender, TestCompletedEventArgs e) 
    { 
     var response = e.UserState as Action<TestResponse, Exception>; 

     if (response != null) 
     { 
      var ex = GetServiceException(e); 

      if (ex == null) 
      { 
       response(e.Result, null); 
      } 
      else 
      { 
       response(null, ex); 
      } 
     } 
    } 
} 

Vì vậy, trong thử nghiệm của tôi những gì tôi đang thực sự làm được chế giễu ISerivceProxy và đi qua nó và chỉ cố gắng để thử nghiệm một dịch vụ gọi để đảm bảo bao bọc nó gọi hành động một cách chính xác:

[TestMethod] 
[Asynchronous] 
public void Test_Returns_Expected() 
{ 
    var mockProxy = new Mock<IServiceProxy>(); 
    var helper = new HelperClient(mockProxy.Object); 
    bool expectedResult = true; 
    var result = new TestResponse() { Value = expectedResult }; 

    this.mockProxy.Setup(
     p => p.TestAsync(It.IsAny<TestRequest>())) 
     .Raises(p => p.TestCompleted += null, new TestCompletedEventArgs(new object[] { result }, null, false, null)); 

    helper.Test(new TestRequest(), (response, ex) => 
    { 
     Assert.AreEqual(expectedResult, response.Value); 
     EnqueueTestComplete(); 
    }); 
} 

vấn đề là đối tượng proxy chế giễu là không bao giờ nâng cao sự kiện TestCompleted nên hành động phản ứng của tôi là không bao giờ bị viện dẫn để hoàn tất việc thử nghiệm (mặc dù các thử nghiệm xuất hiện để hoàn thành công Khẳng định là ne ver thực sự chạy). Xin lỗi vì bài đăng dài như vậy, chỉ cố gắng hiển thị cho bạn nhiều mã nhất có thể.

EDIT 2

Added [Asynchronous] và gọi đến EnqueueTestComplete() mà tôi nhận ra rằng tôi có thể cần phải thực hiện các thử nghiệm chờ đợi cho sự kiện này được nâng lên.Điều này đã không thực sự giúp đỡ, sự kiện này vẫn chưa bao giờ được nêu ra để thử nghiệm chỉ bị treo và không bao giờ hoàn thành.

EDIT 3

câu trả lời Aliostad là đúng khi cho rằng chữ ký thiết lập kỳ vọng của tôi không khớp với chữ ký thực tế thử nghiệm() cho phép tôi vượt qua trong một hành động phản ứng như param thứ hai. Sai lầm ngu ngốc, nhưng đó là những gì đã ngăn cản Moq từ việc nâng cao sự kiện đã hoàn thành. Tôi cũng đã quên chuyển Action thành đối tượng userState trong TestCompletedEventArgs để nó thực sự được gọi khi sự kiện Completed được nâng lên. Ngoài ra, [Asynchronous]EnqueueTestCompleted dường như không cần thiết trong trường hợp này.

đây được cập nhật mã kiểm tra cho bất cứ ai quan tâm:

[TestMethod] 
public void Test_Returns_Expected() 
{ 
    var mockProxy = new Mock<IServiceProxy>(); 
    var helper = new HelperClient(mockProxy.Object); 
    bool expectedResult = true; 
    var result = new TestResponse() { Value = expectedResult }; 

    Action<TestResponse, Exception> responseAction = (response, ex) => 
    { 
     Assert.AreEqual(expectedResult, response.Value); 
    }; 

    this.mockProxy.Setup(
     p => p.TestAsync(It.IsAny<TestRequest>(), It.IsAny<Action<TestResponse, Exception>>())) 
     .Raises(p => p.TestCompleted += null, new TestCompletedEventArgs(new object[] { result }, null, false, responseAction)); 

    helper.Test(new TestRequest(), responseAction); 
} 
+1

Xin chào, tôi đã cập nhật câu trả lời của mình. Vấn đề của bạn là đặt kỳ vọng vào một phương thức có chữ ký khác với chữ ký bạn đang gọi trong lớp trợ giúp của bạn. – Aliostad

Trả lời

4

sự kiện Mocking là khá đau đớn và kiểm tra đơn vị trở nên giòn. Nhưng như bạn nói không có cách nào xung quanh nó. Nhưng thông thường bạn sẽ thực hiện cuộc gọi mà bạn đang cố gắng kiểm tra và chặn luồng hiện tại (sử dụng chế độ Ngủ hoặc các phương thức khác) cho đến khi sự kiện được nâng lên (hoặc hết thời gian chờ).

Nó thực sự không rõ ràng những gì bạn đang thử nghiệm. Tôi có thể thấy một mô hình và một phản ứng, đâu là đối tượng thực sự thực sự?

Tôi sẽ cập nhật câu trả lời của mình cho phù hợp.

CẬP NHẬT

tôi có thể thấy một vấn đề ở đây:

helper.Test(new TestRequest(), (response, ex) => 
{ 
    Assert.AreEqual(expectedResult, response.Value); 
    EnqueueTestComplete(); 
}); 

trong báo cáo kết quả cuối cùng, bạn đang đặt EnqueueTestComplete(); và bạn khẳng định nhưng hành động này sẽ không bao giờ được sử dụng bởi vì nó được truyền cho đối tượng moq.

Ngoài ra bạn đang đặt kỳ vọng cho TestAsync(It.IsAny<TestRequest>())) (một đối số) trong khi bạn đang gọi nó với hai đối số trong HelperClient (this.proxy.TestAsync(request, response);) và đó là lý do tại sao nó không bao giờ bị sa thải.

+0

Cảm ơn sự giúp đỡ, tôi đã hoàn thành bỏ qua sự không phù hợp chữ ký đó là toàn bộ vấn đề. Tôi đã chỉnh sửa câu hỏi trên để cung cấp thêm một số mã về cách cuối cùng tôi đã làm việc đó. –

+0

Không có vấn đề giao phối. Chúc mừng sắp xếp. – Aliostad

0

vừa tìm kiếm máy khách WCF không đồng bộ giả và tìm thấy câu hỏi này.

để ngăn chặn tình huống này Moq có thể .Verify() rằng p.TestAsync() đã được gọi.

//will throw MockException if p.TestAsync() has never been called. 
this.mockProxy.Verify(p => p.TestAsync(It.IsAny<TestRequest>()), Times.Once()); 
Các vấn đề liên quan