How to mock HttpContext.Current.Items with NUnit and Rhino Mocks - c#

I'm using NUnit and RhinoMocks for unit testing on the (WebApi) project.
There is a method I'm trying to write test for, which is supposed to add an item to HttpContext.Current.Items.
public override void OnActionExecuting(HttpActionContext actionContext)
{
HttpContext.Current.Items.Add("RequestGUID", Guid.NewGuid());
base.OnActionExecuting(actionContext);
}
I have no idea how can I make HttpContext.Current.Items available to the method when ran from within a test method. How can I achieve this?
Also, how can I check if the item has been added (what kind of assertion can/should I use)

You don't need to refactor your code\use RhinoMocks at all for testing it.
Your UT should be similar to the following example:
[Test]
public void New_GUID_should_be_added_when_OnActionExecuting_is_executing()
{
//arrange section:
const string REQUEST_GUID_FIELD_NAME = "RequestGUID";
var httpContext = new HttpContext(
new HttpRequest("", "http://google.com", ""),
new HttpResponse(new StringWriter())
);
HttpContext.Current = httpContext;
//act:
target.OnActionExecuting(new HttpActionContext());
//assert section:
Assert.IsTrue(HttpContext.Current.Items.Contains(REQUEST_GUID_FIELD_NAME));
var g = HttpContext.Current.Items[REQUEST_GUID_FIELD_NAME] as Guid?;
if (g == null)
{
Assert.Fail(REQUEST_GUID_FIELD_NAME +
" is not a GUID, it is :: {0}",
HttpContext.Current.Items[REQUEST_GUID_FIELD_NAME]);
}
Assert.AreNotEqual(Guid.Empty, g.Value);
}
BTW, you can split this test to 2:
verifies that the RequestGUID is being populated with a GUID
verifies that the GUID is not Guid.Empty

Related

Unit test result in null object while testing a web api 2

I am new to MS Unit Testing and Moq objects. I am trying to test my Web API 2 controller. I have given below my unit test and controller code. While stepping through the code, it doesn't even go to the GetDeliveryCodeStrategy method.
[TestMethod]
public void CreateDelivery_ShouldReturnDeliveryCode()
{
Mock<IDeliveryStrategy> deliveryStrategy = new Mock<IDeliveryStrategy>
();
Mock<IDeliveryCode> deliveryCode = new Mock<IDeliveryCode>();
var controller = new DeliveryCodeController(deliveryStrategy.Object,
deliveryCode.Object);
var controllerContext = new HttpControllerContext();
var request = new HttpRequestMessage();
request.Headers.Add("appToken", "a57ffa87-950e-40f4-b965-17788becac7d");
controllerContext.Request = request;
controller.ControllerContext = controllerContext;
var result = controller.CreateDelivery(50) as
CreatedNegotiatedContentResult<IDeliveryCode>;
Assert.IsNotNull(result);
}
public class DeliveryCodeController : ApiController
{
IDeliveryStrategy _deliveryBatch;
IDeliveryCode _deliveryCode;
//Constructor dependency injection through Autofac
public DeliveryCodeController(IDeliveryStrategy DeliveryBatch,
IDeliveryCode deliveryCode)
{
_deliveryBatch = DeliveryBatch;
_deliveryCode = deliveryCode;
}
[HttpPost]
[Route("api/DeliveryCode/{percentage}")]
public IHttpActionResult CreateDelivery(int percentage)
{
String appToken = String.Empty;
if (Request.Headers.TryGetValues("appToken", out IEnumerable<String>
headerValues))
{
appToken = headerValues.FirstOrDefault();
}
if (!String.IsNullOrEmpty(appToken)))
{
IDeliveryContext deliveryContext =
_deliveryBatch.GetDeliveryCodeStrategy(percentage);
_deliveryCode.Code = deliveryContext.Create();
return Created(Request.RequestUri.ToString(), _deliveryCode);
}
else
{
return Content(HttpStatusCode.Forbidden, new Error { message = "The App
Token is not valid." });
}
}
}
When I do the "Debug Test" and step through the code, the deliveryContext
object comes as null in the code IDeliveryContext deliveryContext =
_deliveryBatch.GetDeliveryCodeStrategy(percentage);
You have to set up the Mock to return a certain value:
IDeliveryContext deliveryContext = // ???? - whatever you want it to be.
// Could be another Mock.
// This is what the Mock will return.
Mock<IDeliveryStrategy> deliveryStrategy = new Mock<IDeliveryStrategy>();
deliveryStrategy.Setup(x => x.GetDeliveryCodeStrategy(It.IsAny<decimal>()))
.Returns(deliveryContext);
This tells the Mock that that when its GetDeliveryCodeStrategy method is called, it should return the specified IDeliveryContext. Depending on what you're trying to do, that could be another Mock. (Mocks that return mocks are undesirable, but if you're starting out I'd file that detail away and come back to it.)
I'm guessing that percentage is a decimal. It.IsAny<decimal>() means that the mock doesn't care what the value is. That's usually okay because what you're testing is what your class does with the object returned by the mock.
You need to call Setup() on mock objects for the methods that you want to use:
var deliveryStrategy = new Mock<IDeliveryStrategy>();
deliveryStrategy.Setup(x => x.GetDeliveryCodeStrategy(It.IsAny<int>))
.Returns(AMockOfDeliveryContext); //you need to mock it beforehand so you can
//use the object here

Mock testing of tweets received and responded to

I have two interfaces called ITweetReq and ITweetResp.
An outside service sends Requests to send tweets when they come in, which is implemented by the interface ITweetReq and our system in return sends the reply back which is implemented in ITweetResp interface.
Both the incoming and outgoing messages are logged in a file. I have to unit test the log file to make sure it is logging the correct number of message received and replied.
I am wondering if I should mock both the interfaces then do a test on the log file, but not sure how to go about it. Any help or suggestion will be appreciated.
I am using NUnit and Moq Framework.
var TweetReq = new Mock<ITweetReq>();
var TweetRes = new Mock<ITweetRes>();
You seem a little confused as to what mocking/unit testing is.
Mocks are typically created for anything 'outside' of the class being tested.
Unit tests are run on your code (typically a method, or part of it).
You should write unit tests for the class which does the logging, by calling the methods which receive/reply to tweets with the mocked objects, and testing for the expected result.
It might be better if you mocked your logging class too, as testing files directly can become complicated and is not recommended.
For example, you might have these methods on your class.
public class TweetHandler
{
public void Main()
{
ILogger logger = GetLogger();
while (true)
{
ITweetReq request = GetNextRequest();
ITweetRes response = HandleRequest(request, logger);
SendResponse(response, logger);
}
}
public ITweetRes HandleRequest(ITweetReq request, ILogger logger)
{
int id = request.Id;
string text = request.Text;
logger.Log("Received tweet " + id + " with text: " + text);
return new TweetResponse(id, text);
}
public void SendResponse(ITweetRes response, ILogger logger)
{
logger.Log("Sending response to tweet: " + response.Id);
Response(reponse);
}
}
You can then write unit tests like this:
[TestMethod]
public void HandleRequest_ShouldLogIdAndText()
{
// Arrange
var handler = new TweetHandler();
var mockRequest = new Mock<ITweetReq>();
var mockLogger = new Mock<ILogger>();
mockRequest.Setup(x => x.Id).Returns(10);
mockRequest.Setup(x => x.Text).Returns("some text");
// Act
handler.HandleRequest(mockRequest, mockLogger);
// Assert
mockLogger.Verify(x => x.Log("Received tweet 10 with text: some text"));
}
[TestMethod]
public void SendResponse_ShouldLogId()
{
// Arrange
var handler = new TweetHandler();
var mockResponse = new Mock<ITweetRes>();
var mockLogger = new Mock<ILogger>();
mockResponse.Setup(x => x.Id).Returns(20);
// Act
handler.SendReponse(mockResponse, mockLogger);
// Assert
mockLogger.Verify(x => x.Log("Sending response to tweet: 20"));
}

Problems when mocking HttpResponeBase and HttpRequestBase

I got a mvc 3 project where I want to mock HttpResonseBase and HttpRequestBase. Im using RhinoMocks 3.6 to mock myobjects. My test code rightnow looks like this.
[TestMethod]
public void Test()
{
MockRepository repo = new MockRepositoy();
HttpContextBase mockHttpContext= repo.StrictMock<HttpContextBase>();
HttpRequestBase mockRequest = repo.StrictMock<HttpRequestBase>();
HttpResponseBase mockResponse = repo.StrictMock<HttpResponseBase>();
ICookie mockCookie = repo.StrictMock<ICookie>();
Controller instanceToTest = new Controller(mockCookie);
SetupResult.For(mockHttpContext.Request).Return(mockRequest);
SetupResult.For(mockHttpContext.Response).Return(mockResponse);
mocks.Replay(context);
instanceToTest.ControllerContext = new ControllerContext(mockHttpContext, new RouteData(), instanceToTest);
mockCookie.Expect(x=>x.MethodToExpect("Test",mockRequest,mockResponse);
mockRepository.ReplayAll();
instanceToTest.MethodToTest();
mockRepository.VerifyAll();
}
When im running the test I get this errormessage;
Rhino.Mocks.Exceptions.ExpectationViolationException: ICookie.MethodToExpect("Test", System.Web.HttpResponseBase, System.Web.HttpRequestBase); Expected #0, Actual #1.
ICookie.MethodToExpect("Test", HttpResponseBaseProxy); Expected #1, Actual #0.
What am I doing wrong?
The problem here is that you use StrictMock - it means that if you call a method on the Mock object that you haven't set any expectations on it, VerifyAllExpectations will fail. You could use MockRepository.GenerateMock<T> method instead of the StrictMock.
Another comment is that you'd better stick with the RhinoMocks AAA syntax (using the Expect, Stub and VerifyAllExpectations methods instead of ReplayAll, SetupResult etc...)
Here's how your code may look like with pure AAA syntax:
[TestMethod]
public void Test()
{
// Arrange(A) - create your objects, mocks and stubs
// The context is a Stub - you just want it to return the mocked request and response
HttpContextBase mockHttpContext= MockRepository.GenerateStub<HttpContextBase>();
HttpRequestBase mockRequest = MockRepository.GenerateMock<HttpRequestBase>();
HttpResponseBase mockResponse = MockRepository.GenerateMock<HttpResponseBase>();
ICookie mockCookie = MockRepository.GenerateMock<ICookie>();
Controller instanceToTest = new Controller(mockCookie);
// Stub will return the mocked request and response on every call (similar to SetupResult)
mockHttpContext.Stub(x => x.Request).Return(mockRequest);
mockHttpContext.Stub(x => x.Response).Return(mockResponse);
instanceToTest.ControllerContext = new ControllerContext(mockHttpContext, new RouteData(), instanceToTest);
mockCookie.Expect(x=>x.MethodToExpect("Test",mockRequest,mockResponse);
// Act(A) - do the actual operations on the tested class
instanceToTest.MethodToTest();
// Assert (A) - Verify your expectations
mockCookie.VerifyAllExpectations();
}

How can I mock Request.Url.GetLeftPart() so my unit test passes

my code does this
string domainUrl = HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority);
int result = string.Compare(domainUrl, "http://www.facebookmustdie.com");
// do something with the result...
How can I mock this so my unit test passes, do I have to mock the whole HttpContext class? And if that was the case how would I inject that into the code so the 'correct' HttpContext is used when the unit test is run
You don't need to mock it:
var sb = new StringBuilder();
TextWriter w = new StringWriter(sb);
var context = new HttpContext(new HttpRequest("", "http://www.example.com", ""), new HttpResponse(w));
HttpContext.Current = context;
Console.WriteLine(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority));
The HttpContext singleton can't be easily mocked, and don't play well with unit testing either, because it ties you with the IIS infrastructure.
It's true that Moles can do the job too, but the true issue is the heavy couplage with IIS.
You should rather pass the relevant request data (url for exemple in your case) to your function or class, in order to be able to isolate your logic from the infrastructure. This way, you will be able to separate it from IIS, and run it on a testing infrastructure easily.
Basically, there are two possibilities:
Use TypeMock Isolator or Moles to mock HttpContext.
Introduce an interface for the whole HttpContext class or just for a UrlHelper and pass an instance of a class that implements that interface into your class. Keyword: Dependency Injection (DI)
I don't know what type of project you're writing this code for, but if it's an MVC project I'd suggest re-writing your code to use HttpContextBase instead - if that's possible. Then you can create a stub or mock of this and inject that for your tests. Request.Url returns System.Uri so you'll have to create an instance of this and set that on your context stub/mock.
Example for above :
namespace Tests
{
[TestClass()]
public class MyTests
{
[ClassInitialize()]
public static void Init(TestContext context)
{
// mock up HTTP request
var sb = new StringBuilder();
TextWriter w = new StringWriter(sb);
var httpcontext = new HttpContext(new HttpRequest("", "http://www.example.com", ""), new HttpResponse(w));
HttpContext.Current = httpcontext;
}
[TestMethod()]
public void webSerivceTest()
{
// the httpcontext will be already set for your tests :)
}
}
}

Invocation was not performed on the mock, what could be wrong here?

this error is trown by the following TEST. If i test the DataLayer, the database gets updated and everything works. however the mock keeps sending out this error. i have a similar test that does work with almost the exact code (on the InsertRPAData). the only diffrence i can see is that the XMLDataEntity is a diffrent entity in the test compared to the Verify but both of them use the barcode = 1 though.
this test needs to be worked on and the XMLDataEntity is just there to allow me to verefy the Test. also ignore the return for now.
[TestInitialize]
public void TestInitialize()
{
_mockRepository = new Mock<IRPADataLayer>();
UnityUtil.UnityContainer = new UnityContainer();
UnityUtil.UnityContainer.RegisterInstance(typeof(IRPADataLayer), _mockRepository.Object);
}
[TestMethod]
public void TestDoSuppressions()
{
//Arange
var suppressiontest = new Suppression();
//Import the XML File
XElement newElement = XElement.Parse(get090XML());
XDocument testdoc = new XDocument();
testdoc.Add(newElement);
String string2Stream = String.Concat("1");
Stream reader = new MemoryStream(ASCIIEncoding.Default.GetBytes(string2Stream));
RPADataEntity rpa = new RPADataEntity();
XMLDataEntity test = new XMLDataEntity();
test.barcode = 1;
rpa.RPAID = 1;
rpa.XMLData = testdoc;
//Act
Int32 success = suppressiontest.DoSuppressions(reader, rpa);
//Assert
_mockRepository.Verify(x => x.UploadPreprocData(rpa, test));
}
The method being called is this one.
public Int32 DoSuppressions(Stream reader, RPADataEntity rpa)
{
XMLDataEntity test = new XMLDataEntity();
test.barcode = 1;
_IRPADataLayer.UploadPreprocData(rpa, test);
return 1;
}
and the interface is this
public interface IRPADataLayer
{
void InsertPreProcData(PreProcDataEntity PreProcDataEntity);
void InsertRpaData(RPADataEntity RPADataEntity);
RPATypeEntity GetRPAType(String type);
void UploadPreprocData(RPADataEntity rpa, XMLDataEntity xml);
}
Your verify is expecting a certain instance of XMLDataEntity, (the one your instantiating in your test).
However the method that is being tested creates it's own XMLDataEntity and calls UploadPreprocData.
So the verification fails because the method hasn't been called with the expected instance of XMLDataEntity.
Most mocking frameworks provide a way to to specify that the expected parameter can be of any instance, so that might be what your wanting here.
Hope that helps.
Edit:
In Moq, verifying and excepting any parameter of a given type is done by using:
It.IsAny<T>()
Where T is the type of the expected instance.
In your case this can be done like so:
_mockRepository.Verify(x => x.UploadPreprocData(rpa, It.IsAny<XMLDataEntity>()));

Categories