Aleksej_Shherbak
Aleksej_Shherbak

Reputation: 3068

How to mock a Save method behavior for testing my repository?

I have the following repository:

public class WorkspaceRepo : IWorkspacesRepo
{
    private readonly ApplicationContext _applicationContext;

    public WorkspaceRepo(ApplicationContext applicationContext)
    {
        _applicationContext = applicationContext;
    }

    public IEnumerable<Workspace> Workspaces => _applicationContext.Workspaces;

    public void Save(Workspace workspace)
    {
        _applicationContext.Workspaces.Add(workspace);
        _applicationContext.SaveChanges();
    }
}

And the following method is from my business logic class. I need to test this method:

public Workspace CreateWorkspace(Workspace workspace)
{
    if (string.IsNullOrEmpty(workspace.UserUuid))
    {
        throw new RpcException(new Status(StatusCode.NotFound, "Empty user Uuid"));
    }

    var freSlots =  10 - _workspacesRepo.Workspaces.Count(x => x.UserUuid == workspace.UserUuid);

    if (freSlots <= 0)
    {
        throw new RpcException(new Status(StatusCode.Aborted, "There are no free slots work workspaces"));
    }

    _workspacesRepo.Save(workspace);

    return workspace;
}

The business logic is simple. I can save only 10 Workspace object. The next saving must give me RpcException. Now I would like to test it. Here is the test code:

[Test]
public void User_Cant_Exceed_Workspaces_Limit()
{
    // organization
    Mock<IWorkspacesRepo> mock = new Mock<IWorkspacesRepo>();
    mock.Setup(m => m.Save(It.IsAny<Workspace>())).Callback( /* what to do here?*/ )    

    var target = new WorkspaceBusinessService(mock.Object, null);

    for (var i = 0; i < 10; i++)
    {
        target.CreateWorkspace(new Workspace
        {
            Name = Guid.NewGuid().ToString(),
            UserUuid = Guid.NewGuid().ToString(),
            WorkspaceId = i + 1
        });
    }

    var redundantWorkspace = new Workspace
    {
        Name = Guid.NewGuid().ToString(),
        UserUuid = Guid.NewGuid().ToString(),
        WorkspaceId = 11
    };

    // action
    // asserts
    var ex = Assert.Throws<RpcException>(() => target.CreateWorkspace(redundantWorkspace));
    Assert.That(ex.Message, Is.EqualTo("Status(StatusCode.Aborted, \"There are no free slots work workspaces\")"));
}

But expected behavior is not going on. I watched this with debug and in the CreateWorkspace method I have always 10 freeSlots. How to test this situation?

Upvotes: 1

Views: 814

Answers (1)

Nkosi
Nkosi

Reputation: 247108

Based on the Logic in the method under test, you are mocking the wrong member.

Mock Workspaces property so that it behaves as expected when

//..

var freSlots = 10 - _workspacesRepo.Workspaces.Count(x => x.UserUuid == workspace.UserUuid);

if (freSlots <= 0) {

//...

is invoked.

For example

// Arrange
//need common user id
var userUuid = Guid.NewGuid().ToString();

//create workspaces to satisfy Linq Count(Expression)
var workspaces = Enumerable.Range(0, 10).Select(i => new Workspace {
    Name = Guid.NewGuid().ToString(),
    UserUuid = userUuid, //<-- Note the common user id
    WorkspaceId = i + 1
});

Mock<IWorkspacesRepo> mock = new Mock<IWorkspacesRepo>();

//set up the property to return the list
mock.Setup(_ => _.Workspaces).Returns(workspaces);

var target = new WorkspaceBusinessService(mock.Object, null);

var redundantWorkspace = new Workspace {
    Name = Guid.NewGuid().ToString(),
    UserUuid = userUuid, //<-- Note the common user id
    WorkspaceId = 11
};

// Act
Action act = () => target.CreateWorkspace(redundantWorkspace);

//Assert
var ex = Assert.Throws<RpcException>(act);
Assert.That(ex.Message, Is.EqualTo("Status(StatusCode.Aborted, \"There are no free slots work workspaces\")"));

Upvotes: 2

Related Questions