如何模拟两个连续的Web请求

时间:2013-06-21 10:51:41

标签: asp.net-mvc-3 unit-testing c#-4.0 httpwebrequest moq

我正在尝试测试一个连续发出两次Web请求的方法。

到目前为止,我只使用this solution using an object called TestWebRequest测试了单个请求,这就像单个请求的魅力一样。如果你不熟悉它,TestWebRequest拦截Web请求机制并在场景后面工作以返回预期的响应。这使得可以在不使用模拟的情况下测试实际服务。

但是现在我的一个方法的逻辑变成了这样的东西(在伪代码中)

public void MakePayment(PaymentRequest request)
{
    var statusRequest = webService.GetPaymentStatus(new PaymentStatusRequest()
            {
                OrderId = request.OrderId
            });

    if (statusRequest.StatusId != 100)
    {
     var responseXml = webService.GetResponse(GetRequestXml(request));
     /*.. process response ..*/
    }
}

有没有办法扩展TestWebRequest来处理两个请求,还是有其他方法可以用来测试这个方法?

以下是工作测试的示例:

 [Test]
 public void MakePayment()
 {
      var response = @"<XML>..</XML>";
      TestWebRequest request = TestWebRequestCreate.CreateTestRequest(response);
      var result = webService.MakePayment(1, new PaymentRequest());
      var expectedResponse = new PaymentResponse()
      {
          Status = 23
      };
      Assert.AreEqual(expectedResponse, result);  
 }

现在,如果MakePayment突然发出两个请求,那么我们需要一种模拟两个假响应的方法:

 [Test]
 public void MakePayment()
 {
      var response1 = @"<XML>..</XML>";
      var response2 =  @"<XML>..</XML>";
      TestWebRequest request1 = TestWebRequestCreate.CreateTestRequest(response1);
      TestWebRequest request2= TestWebRequestCreate.CreateTestRequest(response2);
      var result = webService.MakePayment(1, new PaymentRequest());
      var expectedResponse = new PaymentResponse()
      {
          Status = 23
      };
      Assert.AreEqual(expectedResponse, result);  
 }

哪个不起作用。

提前致谢

2 个答案:

答案 0 :(得分:0)

您是否测试了您作为工作测试提供的示例?这不会通过,因为expectedResponse在您的测试代码中被实例化,并且不能与从webService.MakePayment调用返回的对象相同。您链接的文章是测试2个字符串是否相等,而不是2个复杂类型。您实际上也没有使用在测试中实例化的TestWebRequest对象。

也就是说,您可以通过控制创建并传递给webRequest.MakePayment的2个调用的2个请求或使用Moq的回调功能来完成您要测试的内容。像这样(未经测试的代码):

webRequestMock.Setup(x => x.MakePayment(1, It.IsAny<PaymentRequest>()).Returns(It.IsAny<PaymentResponse>()).CallBack((PaymentRequest request, PaymentResponse response) => VerifyResponse(request, response));

private void VerifyResponse(PaymentRequest request, PaymentResponse response) 
{
    // do some checks to determine whether it's the first call or the second, based on something uniquely different between to 2 requests - I need more actual code from you before I can tidy this up
    // e.g. (pseudocode)
    if (request.SomeValue == firstRequestValue) 
    {
        response.ShouldEqual(firstReponse);
    }
    else 
    {
        response.ShouldEqual(secondReponse);
    }

}

我说这是未经测试的代码,因为我不确定是否可以捕获返回的响应并将其传递给回调(因为它是返回值)。

答案 1 :(得分:0)

我通过更新TestWebReqestCreate工厂方法来接受两个请求。

这是更新的代码。它不是很优雅,但适用于两个请求,您不必为单个请求更改所有现有测试。

我想它可以更新以链接任意数量的请求,但我现在不需要这样做,所以我想出了一些快速的东西。

我希望帮助那些像我一样被困的人

internal class TestWebRequestCreate : IWebRequestCreate
    {
        static WebRequest nextRequest;
        static WebRequest nextRequest2;
        private static bool used = false;
        static object lockObject = new object();

        static public WebRequest NextRequest
        {
            get { return nextRequest; }
            set
            {
                lock (lockObject)
                {
                    nextRequest = value;
                }
            }
        }

        /// <summary>See <see cref="IWebRequestCreate.Create"/>.</summary>
        public WebRequest Create(Uri uri)
        {
            if (used)
            {
                return nextRequest2;
            }
            else
            {
                used = true;
                return nextRequest;
            }
        }

        /// <summary>Utility method for creating a TestWebRequest and setting
        /// it to be the next WebRequest to use. It can now accept a subsequent request</summary>
        /// <param name="response1">The response the TestWebRequest will return.</param>
        /// <param name="response2">The subsequent response the TestWebRequest will return.</param>
        public static TestWebRequest CreateTestRequest(string response1, string response2 = null)
        {
            TestWebRequest request1 = new TestWebRequest(response1);
            used = false;
            nextRequest = request1;

            if (!string.IsNullOrEmpty(response2))
            {
                TestWebRequest request2 = new TestWebRequest(response2);
                nextRequest2 = request2;
            }

            return request1;
        }
    }
相关问题