如何创建用于在存储库中添加项目的单元测试?

时间:2018-10-17 12:30:14

标签: c# nunit moq

我有一个 IUnitOfWork 接口,该接口封装了我的自定义存储库。我的自定义存储库又继承自 IRepository 界面。

// 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
}

我正在尝试对AddEmployee()方法进行单元测试,因为出现此错误:

该模拟对象预期被调用一次,但被调用0次:uow => uow.Employees.Add(Employee) 配置的设置: IUnitOfWork uow => uow.Employees.Add(员工) 执行的调用: IRepository`1.Add(Employee)

这是我的单元测试

[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);
}

3 个答案:

答案 0 :(得分:2)

您的答案在您的答案中提供的测试(下面复制)通过的原因是您的答案失败了,这是因为您的答案是希望使用您正在使用的特定参考变量(在本例中为_employee)调用该模拟。也许您希望Moq和.Verify()使用.equals()而不是==来检查是否相等?

在被测方法的上下文中,这是正确且理想的-基于测试的名称,您只是想测试该方法确实将您的输入映射到Employee并调用存储库的add方法。如果要确保数据不会在映射中丢失,可以使用It.Is(),它带有一个函数,可用于断言输入的质量(例如,与期望值匹配的名称)。 / p>

如果您只是想测试映射是否成功,则可能对Automapper Configuration Validation作为单独的测试感兴趣。

[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);
}

答案 1 :(得分:0)

通过更改单元测试,我设法使其正常工作

[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);
}

有人可以帮助我了解使用It.IsAny<Employee>()_employee变量的区别吗?


更新

可以在Thorin's answer上找到说明。

答案 2 :(得分:-2)

您没有检查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);
}