Sample code for unit testing api controllers

后端 未结 4 868
遥遥无期
遥遥无期 2021-02-04 03:44

Is there an sample code that shows unit testing a controller that inherits from the api controller? I am trying to unit test a POST but it is failing. I believe I need to set up

相关标签:
4条回答
  • 2021-02-04 04:21

    Using AutoFixture, I usually do something like this:

    [Theory, AutoCatalogData]
    public void PostToCollectionReturnsCorrectResponse(
        CategoriesController sut,
        CategoryRendition categoryRendition)
    {
        HttpResponseMessage response = sut.Post(categoryRendition);
    
        Assert.Equal(HttpStatusCode.Created, response.StatusCode);
    }
    

    See this other SO answer for more details about this approach.

    0 讨论(0)
  • 2021-02-04 04:22

    Sample code for unit testing API controller with async fundtion in C#

    1. Prepare test Models:

              using System;
              namespace TestAPI.Models
              {
                  public class TestResult
                  {
                      public DateTime Date { get; set; }
                      public bool Success { get; set; }
                      public string Message { get; set; }
                  }      
              }
      
    2. Prepare test controller

              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. unit test async controller with result check from response

              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);
                      }        
                  }
              }
      
    0 讨论(0)
  • 2021-02-04 04:23

    I've created a general solution for calling some action and getting HttpResponseMessage as Dictionary which is very convenient for usage.

    First some extension for the dictionary:

    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);
            }
        }
    }
    

    Now request creating part:

    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;
        }       
    }
    

    And finally response message to dictionary converter class:

    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...
    

    and usage :

    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());
    
    0 讨论(0)
  • 2021-02-04 04:29

    this code should demonstrate the basics of a post test. Assumes you have a repository injected into the controller. I am using MVC 4 RC not Beta here if you are using Beta the Request.CreateResponse(... is a little different so give me a shout...

    Given controller code a little like this:

    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;
        }
    }
    

    The unit test would look a little like this (NUnit and 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");
    
    0 讨论(0)
提交回复
热议问题