单元测试api控制器的示例代码

时间:2012-04-06 10:31:26

标签: .net unit-testing asp.net-web-api

是否有示例代码显示单元测试从api控制器继承的控制器? 我正在尝试对POST进行单元测试,但它失败了。我相信我需要设置HttpControllerContext进行测试,但不知道如何 感谢

4 个答案:

答案 0 :(得分:10)

此代码应演示后期测试的基础知识。假设您有一个注入控制器的存储库。我在这里使用MVC 4 RC而不是Beta,如果你使用Beta的Request.CreateResponse(......有点不同,请给我一个大喊......

鉴于控制器代码有点像这样:

public class FooController : ApiController
{
    private IRepository<Foo> _fooRepository;

    public FooController(IRepository<Foo> fooRepository)
    {
        _fooRepository = fooRepository;
    }

    public HttpResponseMessage Post(Foo value)
    {
        HttpResponseMessage response;

        Foo returnValue = _fooRepository.Save(value);
        response = Request.CreateResponse<Foo>(HttpStatusCode.Created, returnValue, this.Configuration);
        response.Headers.Location = "http://server.com/foos/1";

        return response;
    }
}

单元测试看起来有点像这样(NUnit和RhinoMock)

        Foo dto = new Foo() { 
            Id = -1,
            Name = "Hiya" 
        };

        IRepository<Foo> fooRepository = MockRepository.GenerateMock<IRepository<Foo>>();
        fooRepository.Stub(x => x.Save(dto)).Return(new Foo() { Id = 1, Name = "Hiya" });

        FooController controller = new FooController(fooRepository);

        controller.Request = new HttpRequestMessage(HttpMethod.Post, "http://server.com/foos");
        //The line below was needed in WebApi RC as null config caused an issue after upgrade from Beta
        controller.Configuration = new System.Web.Http.HttpConfiguration(new System.Web.Http.HttpRouteCollection());

        var result = controller.Post(dto);

        Assert.AreEqual(HttpStatusCode.Created, result.StatusCode, "Expecting a 201 Message");

        var resultFoo = result.Content.ReadAsAsync<Foo>().Result;
        Assert.IsNotNull(resultFoo, "Response was empty!");
        Assert.AreEqual(1, resultFoo.Id, "Foo id should be set");

答案 1 :(得分:1)

使用AutoFixture,我通常会这样做:

[Theory, AutoCatalogData]
public void PostToCollectionReturnsCorrectResponse(
    CategoriesController sut,
    CategoryRendition categoryRendition)
{
    HttpResponseMessage response = sut.Post(categoryRendition);

    Assert.Equal(HttpStatusCode.Created, response.StatusCode);
}

有关此方法的详细信息,请参阅this other SO answer

答案 2 :(得分:0)

我已经为调用某个动作创建了一般解决方案,并将HttpResponseMessage作为字典使用,非常方便使用。

首先是字典的一些扩展名:

public static class DictionaryExtensions
{
    public static void AddRange<T, S>(this Dictionary<T, S> source,
                                      Dictionary<T, S> collection) 
    {
        if (collection == null)
        {
            throw new NullReferenceException("Collection is null");
        }

        foreach (var item in collection)
        {
            source.Add(item.Key, item.Value);
        }
    }
}

现在请求创建部分:

public class RequestCreator
{
    protected static void FirstPart(ApiController controller,
                                    HttpMethod method,String actionUrl)
    {
        // Creating basic request message with message type and requesting 
        // url example : 'http://www.someHostName/UrlPath/'
        controller.Request = new HttpRequestMessage(method, actionUrl);

        // Adding configuration for request
        controller.Request.Properties.
          Add(HttpPropertyKeys.HttpConfigurationKey,new HttpConfiguration());                                         
    }

    protected static Dictionary<String, Object> SecondPart
                                                 (HttpResponseMessage response)
    {
        // Adding basic response content to dictionary
        var resultCollection = new Dictionary<String, Object>
        {
            {"StatusCode",response.StatusCode},
            {"Headers",response.Headers},
            {"Version",response.Version},
            {"RequestMessage",response.RequestMessage},
            {"ReasonPhrase",response.ReasonPhrase},
            {"IsSuccessStatusCode",response.IsSuccessStatusCode}
        };

        var responseContent = response.Content;
        // If response has content then parsing it and 
        // getting content properties
        if (null != responseContent)
        {
            var resultMessageString = response.Content.
                                               ReadAsStringAsync().Result;
            resultCollection.AddRange((new JavaScriptSerializer()).
                                       DeserializeObject(resultMessageString) 
                                               as Dictionary<String, Object>);
        }


        return resultCollection;
    }       
}

最后响应消息到字典转换器类:

public class HttpResponseModelGetter : RequestCreator
{
    public Dictionary<String, Object>
                 GetActionResponse(ApiController controller,HttpMethod method,
                          String actionUrl,Func<HttpResponseMessage> callBack)
    {
        FirstPart(controller, method, actionUrl);
        var response = callBack();
        return SecondPart(response);
    }
}

public class HttpResponseModelGetter<T> : RequestCreator
{
    public Dictionary<String, Object> 
             GetActionResponse(ApiController controller,HttpMethod method,
                String actionUrl,Func<T,HttpResponseMessage> callBack,T param) 
    {
        FirstPart(controller, method, actionUrl);
        var response = callBack(param);
        return SecondPart(response);
    }
}

public class HttpResponseModelGetter<T1,T2> : RequestCreator
{
    public Dictionary<String, Object> 
        GetActionResponse(ApiController controller,HttpMethod method, 
             String actionUrl,Func<T1,T2,HttpResponseMessage> callBack,
             T1 param1,T2 param2)


    {
        FirstPart(controller, method, actionUrl);
        var response = callBack(param1,param2);
        return SecondPart(response);
    }
} 
//and so on...

和用法:

var responseGetter = new HttpResponseModelGetter();
var result = responseGetter.GetActionResponse(controller,HttpMethod.Get,
                    "http://localhost/Project/api/MyControllerApi/SomeApiMethod",
                                              controller.SomeApiMethod);

Boolean isComplete = Boolean.Parse(result["isComplete"].ToString());

答案 3 :(得分:0)

C#

中具有异步资金的单元测试API控制器的示例代码
  1. 准备测试模型:

            using System;
            namespace TestAPI.Models
            {
                public class TestResult
                {
                    public DateTime Date { get; set; }
                    public bool Success { get; set; }
                    public string Message { get; set; }
                }      
            }
    
  2. 准备测试控制器

            using TestAPI.Models;
            using System;
            using System.Net;
            using System.Threading.Tasks;
            using System.Web.Http;
            using System.Web.Http.Description;
    
            namespace TestAPI.Controllers
            {   
                public class TestController : ApiController
                {       
                    public TestController()
                    {           
                    }
    
                    [HttpPost]
                    [ResponseType(typeof(TestResult))]
                    [Route("api/test/start")]
                    public async Task<IHttpActionResult> StartTest()
                    {                                
                        DateTime startTime = DateTime.Now;
                        var testProcessor = new TestAsync();
                        await testProcessor.StartTestAsync();                                     
    
                        HttpStatusCode statusCode = HttpStatusCode.OK;
                        return Content(statusCode, new TestResult
                        {
                            Date = DateTime.Now,
                            Success = true,
                            Message = "test"
                        }); 
                    }       
    
                }
            }
    
  3. 单元测试异步控制器,带有响应结果检查

            using Microsoft.VisualStudio.TestTools.UnitTesting;
            using TestAPI.Controllers;
            using TestAPI.Models;
            using System.Web.Http;
            using System.Threading.Tasks;
            using System.Net;
            using System.Web.Script.Serialization;
    
            namespace Unit.Tests.Controllers
            {
                /// <summary>
                /// Summary description for ControllerTest
                /// </summary>
                [TestClass]
                public class ControllerTest
                {
                    private TestController _testController;       
                    [TestInitialize]
                    public void estAPI_Initializer()
                    {
                        _testController = new TestController();
                        var configuration = new HttpConfiguration();
                        System.Net.Http.HttpRequestMessage request = new System.Net.Http.HttpRequestMessage();
                        request.Headers.Add("Authorization", "Bearer 1232141241");
                        request.Headers.Add("ContentType", "application/json");
                        _testController.Request = request;
                        _testController.Configuration = configuration;            
                    }
    
                    [TestCategory("Unit test")]
                    [TestMethod]
                    public async Task API_Async_Controller_Test()
                    {
                        IHttpActionResult asyncResponse = await _testController.StartTest();
                        var cToken = new System.Threading.CancellationToken(true);           
                        var rResult = asyncResponse.ExecuteAsync(cToken);                      
                        Assert.IsNotNull(rResult);
                        Assert.IsNotNull(rResult.Result);
                        Assert.AreEqual(rResult.Result.StatusCode, HttpStatusCode.OK);
                        Assert.IsNotNull(rResult.Result.Content);
                        var rContent = rResult.Result.Content;
    
                        string data = await rContent.ReadAsStringAsync();
                        Assert.IsNotNull(data);
                        JavaScriptSerializer JSserializer = new JavaScriptSerializer();
                        var finalResult = JSserializer.Deserialize<TestResult>(data);
    
                        Assert.IsNotNull(finalResult);
                        Assert.IsTrue(finalResult.Success);
                    }        
                }
            }