Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock ServiceStackController Cache property?

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?

like image 511
labilbe Avatar asked Jun 14 '17 12:06

labilbe


2 Answers

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.

like image 145
Nkosi Avatar answered Oct 26 '22 00:10

Nkosi


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.

like image 21
mythz Avatar answered Oct 25 '22 23:10

mythz