Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mock server in a Controller

I have the following line in my controller:

string lTempPath = Path.Combine(Server.MapPath("~/Temp"), lRandomFileName);

Problem is Server is not virtual and can only be accessed with a getter.

I get a

"The method or operation is not implemented."

How can I mock this server?

The test I have created is as below:

    [TestCase]
    public void PreviewActionShouldGenerateUrlOfPdf()
    {
        //Arrange
        var server = MockRepository.GenerateMock<HttpServerUtilityBase>();
        server.Stub(s => s.MapPath("~Temp")).Return("~/Temp");
        var httpContext = MockRepository.GenerateMock<HttpContextBase>();
        httpContext.Stub(hc => hc.Server).Return(server);
        httpContext.Server.Stub(s => s.MapPath("~/Temp")).Return("~/Temp");

        var controller = new StudiesController()
        {
            ReportingService = MockRepository.GenerateMock<IReportingService>(),
            SecurityService = MockRepository.GenerateMock<ISecurityService>()
        };


        controller.ControllerContext = new ControllerContext(httpContext, new RouteData(), controller);

        controller.ReportingService.Stub(rs => rs.GetStudyByGID(new Guid())).Return(new Study());
        controller.ReportingService.Stub(rs => rs.ListPractices()).Return(new[] { new Practice(), new Practice() });
        controller.SecurityService.Stub(ss => ss.GetUser("")).IgnoreArguments().Return(new User());

        controller.ControllerContext.HttpContext = MockRepository.GeneratePartialMock<FakeHttpContext>("http://test.com");
        controller.HttpContext.User = new FakePrincipal(new FakeIdentity("test"), new string[0]);
        controller.ControllerContext.HttpContext.Stub(x => x.Request).Return(MockRepository.GenerateMock<HttpRequestBase>());
        controller.ControllerContext.HttpContext.Request.Stub(x => x.Url).Return(new Uri("http://test.com"));



        controller.ReportingService.Stub(
            rs =>
            rs.GenerateReport(new Study(), new Practice(), new User(), false, ReportGenerationOutputFormat.PDF)).IgnoreArguments().Return(new StudyReportSnapshot());

        var content = new ContentResult();

        //Act

        var result = (ContentResult)controller.Preview(new Guid());

        //Assert
        Assert.AreEqual(result.Content, content.Content);

    }
like image 409
willwin.w Avatar asked Jun 26 '13 23:06

willwin.w


People also ask

What is meant by MockServer?

MockServer is designed to simplify integration testing, by mocking HTTP and HTTPS system such as a web service or web site, and to decouple development teams, by allowing a team to develop against a service that is not complete or is unstable.

How do you deploy a MockServer?

Mock server quick startIn Postman, send a request to any API. Your request must be saved to a collection. In the response pane, select Save Response > Save as example. Postman automatically populates the example with the response you received when you sent the request.

How do I use MockServer in JUnit?

MockServer can be run:using a JUnit 4 @Rule via a @Rule annotated field in a JUnit 4 test. using a JUnit 5 Test Extension via a @ExtendWith annotated JUnit 5 class. using a Spring Test Execution Listener via a @MockServerTest annotated test class. as a Docker container in any Docker enabled environment.


2 Answers

Assuming you're using some sort of IOC/DI container, you shouldn't depend on Controller.Server. Instead you should use HttpServerUtilityBase.

This example assumes Ninject as the IOC container, but any of the popular containers will do:

First, register HttpServerUtilityBase with your IOC container like so:

kernel.Bind<HttpServerUtilityBase>().ToMethod(c => new HttpServerUtilityWrapper(HttpContext.Current.Server));

This will make sure that at run time your app will use the current request's server property.

Then, add a constructor to your controller that accepts an instance of HttpServerUtilityBase:

public MyController(HttpServerUtilityBase server)
{
    this._server = server;
}

Now, anywhere before where you were calling Server.MapPath, just call _server.MapPath instead.

Finally, in your tests, you can mock HttpServerUtilityBase like so (assuming Moq as the mocking framework):

var server = new Mock<HttpServerUtilityBase>();
server.Setup(s => s.MapPath(It.IsAny<string>())).Returns<string>(s => /* set up how you want MapPath to behave here */);

EDIT

Since you mentioned you're not using an DI framework, you can resort to "Poor Man's Dependency Injection". Essentially adding an overloaded constructor:

public MyController()
    : this(new HttpServerUtilityWrapper(HttpContext.Current.Server))
{
}

public MyController(HttpServerUtilityBase server)
{
    this._server = server;
}

This will allow production code to use the current web request, but then you can create your own implementation of HttpServerUtilityBase to use for testing.

like image 84
rossipedia Avatar answered Sep 28 '22 08:09

rossipedia


You can use a Mocking framework in your Unit Test code such as Rhino.Mocks, Moq or FakeItEasy

An example unit test body would be (this example uses Moq)

var homeController = new HomeController();

//create mock of HttpServerUtilityBase
var server = new Mock<HttpServerUtilityBase>();

//set up mock to return known value on call.
server.Setup(x => x.MapPath("~/Temp")).Returns("c:\\temp\\");

var httpContext = new Mock<HttpContextBase>();

httpContext.Setup(x => x.Server).Returns(server.Object);

homeController.ControllerContext = new ControllerContext(httpContext.Object, new RouteData(), homeController);

YourModelName yourModelName = new YourModelName();
yourModelName.lRandomFileName = "zzzz.so";

var result = homeController.YourActionName(yourModelName);

Then you can assert the result.

Hope that gives you a few ideas

like image 36
heads5150 Avatar answered Sep 28 '22 07:09

heads5150