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);
}
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.
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.
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.
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 */);
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With