Giving the following ServiceStack controller
public class MyController : ServiceStackController
{
public ActionResult Index()
{
return View(Cache.GetAllKeys());
}
}
and the following test class
[TestFixture]
public class MyControllerTests
{
[Test]
public void Should_call_cache()
{
var controller = new MyController();
// Mock here to access Cache, otherwise throws NullReferenceException
var result = controller.Index();
Assert.IsNotNull(result);
var model = result.Model as IEnumerable<string>;
Assert.IsNotNull(model);
}
}
What is the proper way to mock ICacheClient
Cache property to be able to validate test method?
UPDATE:
As stated by the OP in a comment. The practice of mocking the subject under test is one that is usually avoided. However with the poor design (IMO) of the underlying class that internally is tightly coupled to implementation concerns, making it difficult to test in isolation, then a workaround would be to override the problem member with something that allowed for more control when exercising the test.
Cache
a readonly virtual property, but it can be overridden in a derived class. Use that as the entry point to mocking the desired functionality.
Create a derived class of the class under test and override the Cache
property to return a mock that behaves as expected.
In the following example Moq is used to mock the subject controller and override the Cache
virtual property.
public void _Should_call_cache() {
//Arrange
var controller = Mock.Of<MyController>();
var keys = new[] { "key1", "key2", "key3" };
var cacheMock = new Mock<ICacheClient>();
cacheMock.Setup(_ => _.GetAllKeys()).Returns(keys);
var mockController = Mock.Get(controller);
mockController.CallBase = true;
mockController.Setup(_ => _.Cache).Returns(cacheMock.Object);
//Act
var result = controller.Index() as ViewResult;
//Assert
Assert.IsNotNull(result);
var model = result.Model as IEnumerable<string>;
Assert.IsNotNull(model);
}
I reviewed the ServiceStackController.cs to realize that the readonly property can be overridden.
When testing many ServiceStack components outside of ServiceStack you'll need to wrap it in an AppHost either a SelfHost for integration tests or for unit tests you can use In Memory AppHost with:
using (var appHost = new BasicAppHost {
ConfigureContainer = c => ...,
}.Init())
{
// Test ServiceStack Components...
}
You can use ConfigureContainer
to register any dependencies ServiceStack uses, for Cache Provider ServiceStack uses a MemoryCacheClient by default so you shouldn't need to register anything.
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