I have a web api 2 web service get method. Inside I'm using HttpContext.Current.Request.UserHostAddress. When calling my controller method directly int he unit test this isn't filled in so is errors with null object. So I searched for how to fill this in and found the following which helped with that issue: Add IP address to HttpRequestMessage
However, this needs a server name to send the request to. The problem is that when tests run the VSExpress will need to be running for this API web service, which it won't be when just running the tests. On top of that even if it was it seems it picks a random port to run on so I couldn't hardcode the address like he does in the above link. How can I test my api 2 method given the above issues?
This is the line that blows up when I just test the api method
string ip = HttpContext.Current.Request.UserHostAddress;
[EDIT] Answer
Just so everyone knows here is the solution in code
public class MyController : ApiController
{
private: HttpRequestBase httpRequest;
public MyController()
{
httpRequest = new HttpRequestWrapper(HttpContext.Current.Request)
}
public MyController(HttpRequestBase http)
{
httpRequest = http;
}
public HttpResponseMessage Get()
{
string ip = httpRequest.UserHostAddress;
}
}
I use Moq in the unit test:
Mock<HttpRequestBase> httpRequestMock = new Mock<HttpRequestBase>();
httpRequestMock.Setup(x => x.UserHostAddress).Returns("127.0.0.1");
// then pass httpRequestMock.Object to my controller ctor and good to go
Decouple your controller from the HTTP context. There might be some built-in functionality to do this with which I'm unfamiliar, but one approach would be to simply inject a mockable object. Consider something like this:
public interface IRequestInformation
{
string UserHostAddress { get; }
}
public class RequestInformation : IRequestInformation
{
public string UserHostAddress
{
get { return HttpContext.Current.Request.UserHostAddress; }
}
}
Now you've abstracted the dependency on HttpContext behind an interface. If you're using dependency injection, inject that interface into your controller. If you're not, you can fake it:
// in your controller...
private IRequestInformation _request;
public IRequestInformation RequestInfo
{
get
{
if (_request == null)
_request = new RequestInformation();
return _request;
}
set { _request = value; }
}
Then use that in your controller logic:
string ip = RequestInfo.UserHostAddress;
Now in your unit tests you can supply a mock/fake/etc. for the RequestInfo property. Either create one manually or use a mocking library. If you create one manually, that's simple enough:
public class RequestInformationFake : IRequestInformation
{
public string UserHostAddress
{
get { return "some known value"; }
}
}
Then just supply that to the controller when arranging the test:
var controller = new YourController();
controller.RequestInformation = new RequestInformationFake();
// run your test
Replace your references to HttpContext by references to HttpContextBase. When in your code, initialize the HttpContextBase with a HttpContextWrapper instance, which is a the default behavior implementation in a web stack.
However in your test inject a custom HttpContextBase implementation where you implement the methods and behaviors needed by your test only.
As precised in the link:
The HttpContextBase class is an abstract class that contains the same
members as the HttpContext class. The HttpContextBase class enables
you to create derived classes that are like the HttpContext class, but
that you can customize and that work outside the ASP.NET pipeline.
When you perform unit testing, you typically use a derived class to
implement members with customized behavior that fulfills the scenario
you are testing.
Add the following method to the controller, or inject the equivalent. It uses the magic string MS_HttpContext because that's what the AspNetWebStack implementation uses for exactly the same purpose.
HttpContextBase HttpContextBase => HttpContext.Current != null
? new HttpContextWrapper(HttpContext.Current)
: (HttpContextBase)Request.Properties["MS_HttpContext"]
Replace all other uses of HttpContext.Current in the controller with HttpContextBase.
When unit testing:
var context = new Mock<HttpContextBase>();
...
controller.Request = new HttpRequestMessage();
controller.Request.Properties["MS_HttpContext"] = context.Object;
Related
I am building a Web API application which will be hosted in an IIS environment. In order to perform end to end integration testing of my service(no mocking), I am using OWIN.
The problem is deep down in my service architecture, at the repository layer I am making use of HttpContext.Current to retrieve values from the header(say UserId). See this answer
If you look into the above code, I am making use GetUserInfo method throughout my application to fetch current user information. Another way to do is pass it as a parameter in all method(which I don't personally want to do).
I went through this great answer about including IOwinContext into the repository. I have tried it and it worked for self-hosting, but my end goal is to deploy the application on IIS.
My Questions:
Is there any way my code can handle both the use cases of OWIN self-hosting for integration testing & actual service deployment on IIS?
Is there any issue with my architecture? Something like I shouldn't be using OWIN at all, and use other tools like POSTMAN for testing.
I can post some code if it's required.
Edit:
As suggested by #Nkosi I might have to mock my HeaderService in order to perform integration testing with owin. I am not sure how can I mock one certain method using moq. Here is my code. Its strip down version in order to make as simple as possible.
Code:
public class CreditController : ApiController
{
private readonly ICreditService _creditService;
public CreditController(ICreditService creditService)
{
_creditService = creditService;
}
public IHttpActionResult CreditSummary([FromUri]string requestId)
{
var response = _creditService.GetCreditSummary(requestId);
return Ok(response);
}
}
public class CreditService : ICreditService
{
private readonly IHeaderService _headerService;
private readonly ICreditRepository _creditRepository;
public CreditService(ICreditRepository creditRepository, IHeaderService headerService)
{
_headerService = headerService;
_creditRepository = creditRepository;
}
public CreditObj GetCreditSummary(string req)
{
var userId = _headerService.GetHeaderFromHttpRequest();//Get User
var response = _creditRepository.GetDataFromDatabase(req, userId);
return response;
}
}
public interface IHeaderService
{
string GetHeaderFromHttpRequest();
}
public class HeaderService : IHeaderService
{
public string GetHeaderFromHttpRequest()
{
return HttpContext.Current.Request.Headers["USERID"];
}
}
Below is my code for integration testing: I am using OWIN for self-host. So i want to call the controller method but my GetHeaderFromHttpRequest method should return mock response.
[TestClass]
public class IntegrationTest
{
private static HttpClient _client;
private static IDisposable _webApp;
[ClassInitialize]
public static void Init(TestContext testContext)
{
_webApp = WebApp.Start<Startup>(url: Url);
_client = new HttpClient
{
BaseAddress = new Uri(Url)
};
}
[TestMethod]
public void TestDashboard()
{
var headerStub = new Mock<IHeaderService>();
headerStub.Setup(s => s.GetHeaderFromHttpRequest())
.Returns("MockUserId");
var builder = new UriBuilder(Url + "api/Credit/CreditSummary");
HttpResponseMessage responseMessage = _client.GetAsync(builder.ToString()).Result;
Assert.IsNotNull(responseMessage);
}
}
public class Startup
{
public void Configuration(IAppBuilder app)
{
var config = new HttpConfiguration();
WebApiConfig.Register(config); //This method having all routing/dependancy configuration
app.UseWebApi(config);
}
}
Problem:
When I debug this test case, how do I make sure that _headerService.GetHeaderFromHttpRequest() return mock response. As of now I dont know how can i inject my mocking service to actual controller method call.
Any advise?
Based on #Nkosi's suggestion I was able to mock HeaderService for my integration testing.
Here is the code:
var container = new UnityContainer();
var mock = new Mock<IHeaderService>();
mock.Setup(x => x.GetHeaderFromHttpRequest()).Returns("MockId");
container.RegisterInstance(mock.Object);
I followed this topic and use HttpContextBase in my old project.
Moq: unit testing a method relying on HttpContext
HttpContextWrapper is a wrapper for the HttpContext class, can construct an HttpContextWrapper like this:
var wrapper = new HttpContextWrapper(HttpContext.Current);
You can mock an HttpContextBase and set up your expectations on it using Moq
var mockContext = new Mock<HttpContextBase>();
I have following web Api controller method.
When I run this code through web, HttpContext.Current is never null and give desired value.
public override void Post([FromBody]TestDTO model)
{
var request = HttpContext.Current.Request;
var testName = request.Headers.GetValues("OS Type")[0];
// more code
}
However, when I call this method from Unit Test, HttpContext.Current is always null.
How do i fix it?
During unit tests HttpContext is always null as it is usually populate by IIS. You have a few options around this.
Sure, you could mock the HttpContext, (which you shouldn't really do - Don't mock HttpContext!!!! He doesn't like to be mocked!),. You should really try to stay away from tight coupling with HttpContext all over your code. Try constraining it to one central area (SRP);
Instead figure out what is the functionality you would like to achieve and design an abstraction around that. This will allow for your code to be more testable as it is not so tightly coupled to HttpContext.
Based on your example you are looking to access header values. This is just an example of how to change your thinking when it comes to using HttpContext.
Your original example has this
var request = HttpContext.Current.Request;
var testName = request.Headers.GetValues("OS Type")[0];
When you are looking for something like this
var testName = myService.GetOsType();
Well then create a service that provides that
public interface IHeaderService {
string GetOsType();
}
which could have a concrete implementation like
public class MyHeaderService : IHeaderService {
public string GetOsType() {
var request = HttpContext.Current.Request;
var testName = request.Headers.GetValues("OS Type")[0];
return testName;
}
}
Now in your controller you can have your abstraction instead of having tight coupling to HttpContext
public class MyApiController : ApiController {
IHeaderService myservice;
public MyApiController(IHeaderService headers) {
myservice = headers;
}
public IHttpActionResult Post([FromBody]TestDTO model) {
var testName = myService.GetOsType();
// more code
}
}
You can later inject your concrete type to get the functionality you want.
For testing you then swap dependencies to run your test.
If the method under test is your Post() method you can create a fake dependency or use a mocking framework
[TestClass]
public class MyTestClass {
public class MyFakeHeaderService : IHeaderService {
string os;
public MyFakeHeaderService(string os) {
this.os = os;
}
public string GetOsType() {
return os;
}
}
[TestMethod]
public void TestPostMethod() {
//Arrange
IHeaderService headers = new MyFakeHeaderService("FAKE OS TYPE");
var sut = new MyApiController(headers);
var model = new TestDTO();
//Act
sut.Post(model);
//Assert
//.....
}
}
This is by design and it's always null. But there is a FakeHttpContext project on Nuget that simply you can use it.
To install FakeHttpContext, run the following command in the Package Manager Console (PMC)
Install-Package FakeHttpContext
And then use it like this:
using (new FakeHttpContext())
{
HttpContext.Current.Session["mySession"] = "This is a test";
}
Visit https://www.nuget.org/packages/FakeHttpContext to install the package
See examples on Github: https://github.com/vadimzozulya/FakeHttpContext#examples
Hope this will help :)
All you need is
controller.Request = new HttpRequestMessage();
controller.Configuration = new HttpConfiguration();
From unit-testing-controllers-in-web-api
Here is the scenario:
I'm writing a test for my controller and need to setup a view model titled CheckoutViewModel. My controller method, Products does not take CheckoutViewModel as a parameter, so I cannot pass it in that way.
Currently, the test fails returning a Null Exception because CheckoutViewModel is not getting set and called.
Question: How can I setup my CheckoutViewModel with data.
Error Details:
System.NullReferenceException
Object reference not set to an instance of an object
Current Test
[TestMethod]
public void Products_ProductControllerIsCalled_ReturnsViewWithProducts()
{
// Arrange
var currentSession = _autoMoqer.GetMock<ICurrentSession>().Object;
ProductController productController = new ProductController(currentSession);
var checkoutViewModel = new CheckoutViewModel
{
CheckoutId = new Guid()
};
// Act
ActionResult result = productController.Products();
// Assert
Assert.IsInstanceOfType(result, typeof(ViewResult));
}
Controller
[AccectReadVerbs]
public ActionResult Products()
{
CheckoutViewModel checkoutViewModel = GetCheckoutViewModel();
var checkoutId = checkoutViewModel.CheckoutId;
var result = _productOrchestrator.Products(checkoutId, currentSession)
return View(result);
}
Failing on this method
private CheckoutViewModel GetCheckoutViewModel()
{
if(Session["CheckoutViewModel"] == null)
{
return new CheckoutViewModel();
}
return (CheckoutViewModel)Session["CheckoutViewModel"];
}
If GetCheckoutViewModel has some dependencies on i.e services, dbConnection or other complex classes, you need to add a class with an interface, move the method for GetCheckOutViewModel to the class and take the new interface as a dependency to the controller. Then you need to mock the new interface.
Or edit your viewmodel to take interface dependencies on the stuff that stands in the way of unit testing, i.e the Session.
I think you could create some interface:
public interface ISessionManager
{
Session session {get; set;}
}
Then your controller constructor:
public ProductsController(ISessionManager sm)
{
_sessionManager = sm;
}
Then you can pass a mocked instance to your controller.
I'm guessing that the exceptions is due to the fact that when you're running the unit test there will not be any (webserver) session available. What you want do is to isolate your tests from any external dependencies - and a session state that is part of the webserver hosting environment would be an external dependency.
To solve this you need to either mock or stub out the Session object from your test. There are many ways to do this, but the easiest way would be to make Session a public property on the Controller. From your test you would then set the Session to an instance you create within your test.
I have a method that uses Application variables to get information from an external file. Since Application variables are not used in unit tests, is there a way I can get the Application variables values from my Global.asax file and be able to use them in the test?
This is my test method:
[TestMethod]
public void TestGetCompanyList()
{
var accController = new AccSerController();
CInt cInt = new CInt();
cIn.Iss = "Other";
cIn.Tick = "BK";
var result
= accController.Clist(cIn) as IEnumerable<CList>;
Assert.IsNotNull(result);
}
Use the repository pattern. Your controller shouldn't have any idea about WebConfiguration.
//This defines the stuff that your controller needs (that your repository should contain)
public interface ISiteConfiguration
{
string Setting1 {get; set;}
}
//Use this in your site. Pull configuration from external file
public class WebConfiguration : ISiteConfiguration
{
public string Setting1 {get; set;}
public WebConfiguration()
{
//Read info from external file here and store in Setting1
Setting1 = File.ReadAllText(HttpContext.Current.Server.MapPath("~/config.txt"));
}
}
//Use this in your unit tests. Manually specify Setting1 as part of "Arrange" step in unit test. You can then use this to test the controller.
public class TestConfiguration : ISiteConfiguration
{
public string Setting1 {get; set;}
}
I'm using Ninject to perform dependency injection, but there's lots of other libraries out there. I'm going to omit some basic Ninject setup from my answer, because there's plenty of resources out there. But the below code shows how you'd specify in your web application to use WebConfiguration to fulfill the needs of an ISiteConfiguration.
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ISiteConfiguration>().To<WebConfiguration>();
}
Here's where the magic happens. When an instance of your controller is created in your web application, Ninject will look at the constructor and see that it's asking for ISiteConfiguration. And in your Ninject configuration, you told it to use WebConfiguration when it needs ISiteConfiguration. So Ninject will create a new instance of WebConfiguration and provide (inject) it to your controller.
public class AccountServiceController
{
ISiteConfiguration Config {get; set;}
//This is called constructor injection
public AccountServiceController(ISiteConfiguration config)
{
Config = config;
}
public ActionResult Index()
{
//Now you can use Config without needing to know about ISiteConfiguration's implementation details
//Get settings from Config instead of Application
}
}
You can also use Ninject in unit testing, but here's a simpler demo where we're not using it:
[TestMethod]
public void TestGetCompanyList()
{
//Arrange
var config = new TestConfiguration(){ Setting1 = "mysetting" };
var accountController = new AccountServiceController(config);
}
The result of all this is that you can use your controller's action methods easily for unit testing, because you can use whatever implementation of ISiteConfiguration you want.
I've done the following on some of my tests. Not ideal but it gets the job done.
if (System.Web.HttpContext.Current != null)
{
// Fill your application variable
}
else
{
// Get your data from somewhere else
}
There are two ways of unit testing such scenarios as far as I know.
First one is based on splitting controller function into two: one is controller function itself, another one implements the logic (e.g.: this is the one you test). Example:
Before:
public void MyControllerFunction()
{
var x = Context["variable"];
do-something-with-x;
}
After:
public void MyControllerFunction()
{
var x = Context["variable"];
MyControllerLogic(x);
}
internal void MyControllerLogic(object x)
{
do-something-with-x;
}
And then you test MyControllerLogic() function instead of MyControllerFunction() in unit test
Another methodology is create a surrogate context before invoking unit test.
Example:
var controller = new MyController();
controller.Request = new HttpRequestMessage();
controller.Configuration = new HttpConfiguration();
controller.Request.Content = new StringContent("{ x: 21 }",
Encoding.Unicode);
controller.Request.Content.Headers.ContentType.MediaType =
"application/json";
Please note, I did not create HttpContext in 2nd example, I'm not sure if it's a requirement to have. You probably should be able to create it in similar way as well as the other variables you use. It's sort of a hack anyway, so treat it as such
I'm implementing an oauth provider using DotNetOpenAuth CTP library. So I have created an mvc3 application, which has an OAuth Controller with 3 methods in it with the purpose of authorizing third party applications. The controller has an IOAuthService which encapsulates all the logic that the library must do to complete certain tasks, however, the service methods return DotNetOpenOAuth objects that have their constructors protected.
I would like to test the behavior of the methods within my OAuthController, for this, I'm trying to mock my service methods but I havent't been able to do this. I have to tell moq library what type of object I'm expecting the service method to return, and since I cannot access constructors of these objects, I'm not able to perform a test over my controller method.
The controller:
public class OAuthController : Controller
{
private readonly IOAuthService _oAuthService;
public OAuthController(IOAuthService oAuthService)
{
_oAuthService = oAuthService;
}
[Authorize, AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
public ActionResult Authorize()
{
ClientApplication requestingClient;
var request = _oAuthService.ReadAuthorizationRequest();
if (request == null)
{
throw new HttpException((int)HttpStatusCode.BadRequest, "Missing authorization request.");
}
var response = _oAuthService.RequestClientAuthorization(GetIdentity().Name, out requestingClient, request);
if (response != null)
{
return response.AsActionResult();
}
var model = new AuthorizeClientApplicationViewModel
{
ClientApplication = requestingClient.Name,
Scope = request.Scope,
AuthorizationRequest = request,
};
return View(model);
}
public virtual IIdentity GetIdentity()
{
return User.Identity;
}
}
I want to test that whenever a third party app has no authorization, a view will pop up to the user asking for his permission to authorize the app. Fot this i need to mock:
_oAuthService.RequestClientAuthorization
The setup of my test method will then look like :
var oAuthService = new Mock<IOAuthService>();
oAuthService.Setup(a => a.RequestClientAuthorization(userName, out client, pendingRequest)).Returns(new OutgoingWebResponse()); // DotNetOpenAuth doesn't allow me to do the **new OutgoingWebResponse**
PD: For this question I only wrote one of the controller methods, but there are 3, and they have similar scenarios.
One possibility is to write a wrapper (the same way ASP.NET MVC abstracts all the HTTP Context specific stuff):
public abstract class OutgoingWebResponseWrapperBase
{
protected OutgoingWebResponseWrapperBase() { }
public abstract ActionResult AsActionResult();
}
and then have a naïve implementation:
public class OutgoingWebResponseWrapper: OutgoingWebResponseWrapperBase
{
private readonly OutgoingWebResponse _response;
public OutgoingWebResponseWrapper(OutgoingWebResponse response)
{
_response = response;
}
public override ActionResult AsActionResult()
{
return _response.AsActionResult();
}
}
Now modify the IOAuthService.RequestClientAuthorization method to return a OutgoingWebResponseWrapperBase instead of OutgoingWebResponse.
Just like that:
public interface IOAuthService
{
...
OutgoingWebResponseWrapperBase RequestClientAuthorization(...);
}
Obviously your controller code will stay absolutely the same. It's just that now you can mock the return type of the RequestClientAuthorization in your unit test because it is an abstract class. You can also mock the AsActionResult abstract method call to return some expected mocked instance and you will assert in your unit test that the controller action that you are testing returned this expected action result.
If the constructor is protected, then a derived type could access it. Can you simply use Moq to create a mock of OutgoingWebResponse (which internally will make Moq derive from it and call the protected constructor I think) and return that from your mock method implementation?
Something like this:
System.Net.HttpWebResponse mockResponse; // get this from somewhere
new Moq.Mock<DotNetOpenAuth.Messaging.OutgoingWebResponse>(mockResponse, 5);
This should let you mock up an OutgoingWebResponse. The next problem becomes, where do you get yoru HttpWebResponse instance, since that too has only a protected constructor. You could continue the chain and mock up that the same what as OutgoingWebResponse, and see how far you get.