lord12 lord12 - 16 days ago 5
ASP.NET (C#) Question

How to use Redis in unit testing?

Suppose I have a method in my controller class that updates the score of a key,value pair in a Redis database. I want to write a unit test to check if the score is not null and is incremented by 1. I just want to see how unit testing works with Redis and how you extract the score from a particular key, value pair and check its validity.

Controller Class //When user refreshes api/do/v1/togglelike/{id}", the score is updated in redis for that user and is incremented by 1;

[HttpGet]
[Route("api/do/v1/togglelike/{id}")]
public IHttpActionResult ToggleLike(String id)
{
var currentUser = "mike";


var likeSet = redis1.SortedSetRangeByScore("likes:" + id);
var likeStatus = redis1.SortedSetScore("likes:" + id, currentUser);

//Current user has not yet liked the profile
if (likeStatus == null)
{
redis1.SortedSetAdd("likes:" + id, currentUser, 1);
return Ok("Like Added");

}
/*redis1.SortedSetAdd("likes:" + id, currentUser, 1);
return Ok("Like Added");*/
else
{
double counter = redis1.SortedSetIncrement("likes:" + id, currentUser, 1);
redis1.SortedSetAdd("likes:" + id, currentUser, counter);
return Ok("Like Added");
/*redis1.SortedSetRemove("likes:" + id, currentUser);
return Ok("Like Removed");*/
}
}


Test Class: I want to get the score from the key,value pair and check that it is equal to a valid number;

namespace VideoControllerTest
{
[TestClass]
public class VideoControllerTest
{
IDatabase redis1;

public VideoControllerTest()
{
redis1 = RedisFactory.Connection.GetDatabase();
}

[TestMethod]
public void VideoController_Adview()
{
//Arrange
VideoController controller = new VideoController();
//Act
IHttpActionResult actionResult = controller.ToggleLike("video123");

//Assert; Check to see the counter is incremented by 1 and is not null;

}
}
}

Answer

In order to be able to unit test external system (in this case a redis database), you have to mock the external system.

If the redis1 is an interface, you could easily mock it with a framework like Mock, if it's an implementation this would be hard and you have to wrap it with your own class in order to mock it.

you need to pass the IDatabase into the controller, so I have added another constructor.

class VideoController
{
    private IDatabase redis1;

    public VideoController(IDatabase db)
    {
        this.redis1 = db;
    }
}

Test method should be as follows

//note : library used for mocking is moq (https://github.com/Moq/moq4)
        [TestMethod]
        public void VideoController_Adview()
        {
        //Arrange
            Mock<IDatabase> mockRedis = new Mock<IDatabase>();
            //set existing score as null
            mockRedis.Setup(r => r.SortedSetScore(It.isAny<string>,It.isAny<string>)).Returns(null); 

            VideoController controller = new VideoController(mockRedis.Object);


            //Act
            IHttpActionResult actionResult = controller.ToggleLike("video123");
            //verify added once
            mockRedis.Verify(r => r.SortedSetAdd("likes:videio123",1), Times.Once());
        }