18

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 the HttpControllerContext for testing but don't know how Thanks

1

4 Answers 4

10

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");
Sign up to request clarification or add additional context in comments.

3 Comments

Your post inadvertently uncovered a small bug in my code. I'd left off the third parameter to CreateResponse(..., this.Configuration). As soon as I added it, my null Configuration for my request object was no longer an issue. Hope this helps someone else who's looking
Setting configuration by 'controller.Configuration = new System.Web.Http.HttpConfiguration(new System.Web.Http.HttpRouteCollection());' returned null in my action response returning line, so I've tried this : controller.Request.Properties.Add(HttpPropertyKeys.HttpConfigurationKey, new HttpConfiguration()); and it worked.
-1 That's a horrific quantity of code to put in a unit test. There are better tools
1

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.

Comments

1

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

Comments

0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.