How to Create a Unit Test for Adding Items in a Repository?

99封情书 提交于 2019-12-11 17:32:55

问题


I have an IUnitOfWork interface that encapsulates my custom repositories. My custom repositories in turn inherit from an IRepository interface.

// The class that I am attempting to unit test
// EmployeeBusiness.cs
private readonly IUnitOfWork _unitOfWork;

public EmployeeBusiness(IUnitOfWork unitOfWork)
{
    _unitOfWork = unitOfWork;
}


public EmployeeDto AddEmployee(EmployeeDto employeeDto)
{
    var employee = Mapper.Map<Employee>(employeeDto);

    if (employee == null) return null;

    _unitOfWork.Employees
        .Add(employee);

    _unitOfWork.Complete();

    return Mapper.Map<EmployeeDto>(employee); 
}

// IUnitOfWork interface
public interface IUnitOfWork : IDisposable
{
    IEmployeeRepository Employees { get; }

    void Complete();
}

// IEmployeeRepository interface
public interface IEmployeeRepository : IRepository<Employee> { }

// IRepository<T> interface
public interface IRepository<TEntity> where TEntity : class
{
    void Add(TEntity entity);

    // I have added other methods for simplicity
}

I am struggling with unit testing the AddEmployee() method because I am getting this error:

Expected invocation on the mock once, but was 0 times: uow => uow.Employees.Add(Employee) Configured setups: IUnitOfWork uow => uow.Employees.Add(Employee) Performed invocations: IRepository`1.Add(Employee)

This is my unit test

[SetUp]
public void SetUp()
{
    _employeeDto = new EmployeeDto
    {
        FirstName = "John",
        LastName = "Smith",
        BirthDate = new DateTime(1965, 12, 31)
    };

    _employee = new Employee
    {
       FirstName = "John",
       LastName = "Smith",
       BirthDate = new DateTime(1965, 12, 31)
    };

    _unitOfWork = new Mock<IUnitOfWork>();

    Mapper.Initialize(cfg =>
    {
        cfg.AddProfile<EmployeeProfile>();
    });
}


[Test]
public void AddEmployee_WhenCalled_AddEmployeeToDatabase()
{
    _unitOfWork.Setup(uow => uow.Employees.Add(_employee));
    _employeeBusiness = new EmployeeBusiness(_unitOfWork.Object);

    _employeeBusiness.AddEmployee(_employeeDto);

    _unitOfWork.Verify(uow => uow.Employees.Add(_employee), Times.Once);
    _unitOfWork.Verify(uow => uow.Complete(), Times.Once);
}

回答1:


The reason the test you provided in your answer (copied below) passes when your original fails is because your original was expecting the mock to be called with the specific reference variable you're using (in this case _employee). Perhaps you were expecting Moq and .Verify() to check for equality using .equals() instead of ==?

In the context of your method under test, this is correct and desirable - based on the name of the test you're just looking to test that the method does in fact map your input to an Employee and calls the repository's add method. If you want to make sure that data wasn't lost in the mapping, you could use It.Is(), which takes a function you can use to assert qualities of the input (such as the name matching your expected value).

If you're aiming just to test that the mapping succeeded, you may be interested in Automapper Configuration Validation as a separate test.

[Test]
public void AddEmployee_WhenCalled_AddEmployeeToDatabase()
{
    _unitOfWork.Setup(uow => uow.Employees.Add(_employee));
    _employeeBusiness = new EmployeeBusiness(_unitOfWork.Object);

    var result = _employeeBusiness.AddEmployee(_employeeDto);

    //_unitOfWork.Verify(uow => uow.Employees.Add(_employee), Times.Once); <-- This did not work 

    _unitOfWork.Verify(uow => uow.Employees.Add(It.IsAny<Employee>()), Times.Once); // <-- After changing this to It.IsAny<Employee>() it worked 
    _unitOfWork.Verify(uow => uow.Complete(), Times.Once);
}



回答2:


I have managed to get it to work by changing my unit test

[Test]
public void AddEmployee_WhenCalled_AddEmployeeToDatabase()
{
    _unitOfWork.Setup(uow => uow.Employees.Add(_employee));
    _employeeBusiness = new EmployeeBusiness(_unitOfWork.Object);

    var result = _employeeBusiness.AddEmployee(_employeeDto);

    //_unitOfWork.Verify(uow => uow.Employees.Add(_employee), Times.Once); <-- This did not work 

    _unitOfWork.Verify(uow => uow.Employees.Add(It.IsAny<Employee>()), Times.Once); // <-- After changing this to It.IsAny<Employee>() it worked 
    _unitOfWork.Verify(uow => uow.Complete(), Times.Once);
}

Can anyone please help me understand the difference of using It.IsAny<Employee>() as opposed to the _employee variable?


UPDATE

The explanation can be found at Thorin's answer.




回答3:


You aren't checking the return value of AddEmployee.

[Test]
public void AddEmployee_WhenCalled_AddEmployeeToDatabase()
{
    _unitOfWork.Setup(uow => uow.Employees.Add(_employee));
    _employeeBusiness = new EmployeeBusiness(_unitOfWork.Object);

    var result = _employeeBusiness.AddEmployee(_employeeDto);

    Assert.IsNotNull(result); // <---

    _unitOfWork.Verify(uow => uow.Employees.Add(_employee), Times.Once);
    _unitOfWork.Verify(uow => uow.Complete(), Times.Once);
}


来源:https://stackoverflow.com/questions/52854915/how-to-create-a-unit-test-for-adding-items-in-a-repository

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!