如何断言单元测试方法返回 True

本文关键字:单元 测试方法 返回 True 断言 何断言 | 更新日期: 2023-09-27 18:32:46

这是我的域类

public partial class Department
{
    public int DepartmentId { get; set; }
    [Required]
    public string DepartmentCode { get; set; }
    [Required]
    public string DepartmentFullName { get; set; }
    public bool Status { get; set; }
    public System.DateTime CreatedOn { get; set; }
}

在我的 MVC 应用程序中,这就是我的 DepartmentService 类的样子。

public class DepartmentService : IDepartmentService
{
    private IUnitOfWork _UoW;
    private IRepository<Department> repository;
    public DepartmentService(IUnitOfWork UoW)
    {
        _UoW = UoW;
        repository = _UoW.GetRepository<Department>();
    }
    public IList<Department> GetAllDepartments()
    {
        return repository.GetAll();
    }
    public bool SaveDepartment(Department newDepartment)
    {
        try
        {
            repository.Add(newDepartment);
            _UoW.Save();
        }
        catch (Exception)
        {
            throw;
        }
        return true;
    }
}

我为 GetAllDepartments 方法编写了一个单元测试,如下所示。

[Test]
public void When_GetAllDepartments_Is_Called_RepositoryGetAll_ShouldBeCalled()
{
    // Arrange
    var mockUnitOfWork = new Mock<IUnitOfWork>();
    var mockRepository = new Mock<IRepository<Department>>();
    mockUnitOfWork.Setup(x => x.GetRepository<Department>())
                  .Returns(mockRepository.Object);
    var sut = new DepartmentService(mockUnitOfWork.Object);
    // Act
    sut.GetAllDepartments();
    // Assert
    mockRepository.Verify(x => x.GetAll());
}

我想测试SaveDepartment方法,当部门成功保存时,它应该返回 true。我无法为此编写单元测试。

我还想测试部门代码或部门全名何时为空,如果尝试保存,则应抛出异常。

这就是我到目前为止所拥有的。

[Test]
public void ShouldSucessfully_SaveNewDepartment()
{
    // Arrange
    var mockUnitOfWork = new Mock<IUnitOfWork>();
    var mockRepository = new Mock<IRepository<Department>>();
    Department newDept = new Department { 
          CreatedOn = DateTime.Now,
          Status = true, 
          DepartmentFullName = "DFN", 
          DepartmentCode = "DC" };
    mockUnitOfWork.Setup(x => x.GetRepository<Department>())
                  .Returns(mockRepository.Object);
    var sut = new DepartmentService(mockUnitOfWork.Object);
    // Act
    sut.SaveDepartment(newDept);
    // Assert 
    // ???
}

如何断言单元测试方法返回 True

首先 - 将所有常见的排列代码移动到 SetUp 方法:

private Mock<IUnitOfWork> mockUnitOfWork;
private Mock<IRepository<Department>> mockRepository;
private DepartmentService sut;
[SetUp]
public void SetUp()
{
    mockUnitOfWork = new Mock<IUnitOfWork>();
    mockRepository = new Mock<IRepository<Department>>();
    mockUnitOfWork.Setup(x => x.GetRepository<Department>())
                  .Returns(mockRepository.Object);
    sut = new DepartmentService(mockUnitOfWork.Object);
}
// tests will be here

这将使测试更容易阅读和维护。接下来 - 在命名测试时不要坚持实现:

When_GetAllDepartments_Is_Called_RepositoryGetAll_ShouldBeCalled

如果将存储库方法重命名为 FindAll,该怎么办?如果服务方法将被重命名怎么办?测试已过时。没有人会知道这一点。你应该描述你的SUT应该做什么,而不是如何做:

[Test]
public void ShouldGetAllDepartments()
{
    var expected = new List<Department>{ CreateDepartment(), CreateDepartment()};
    mockRepository.Setup(r => r.GetAll()).Returns(expected);
    var actual = sut.GetAllDepartments();
    Assert.That(actual, Is.EqualTo(expected));
    mockRepository.VerifyAll();
}

如您所见,测试名称已更改。我也在这里验证了不同的东西 - 不仅调用了存储库(实际上可以删除该检查(,而且该服务返回与从存储库获得的完全相同的部门。这就是服务的作用。第二个测试:

[Test]
public void ShouldSucessfullySaveNewDepartment()
{
    var department = CreateDepartment();
    mockRepository.Setup(r => r.Add(department));
    var result = sut.SaveDepartment(department);
    Assert.True(result);
    mockRepository.VerifyAll();
    mockUnitOfWork.Verify(u => u.Save());
}

它验证以下服务行为:服务应传递到与传递给服务完全相同的部门实例的存储库,并且应返回 true,它还调用 save on 工作单元来提交数据。

顺便说一句,正如您在上面看到的,我使用辅助程序方法来使测试更干净:

private Department CreateDepartment()
{
    return new Department { 
        CreatedOn = DateTime.Now, 
        Status = true, 
        DepartmentFullName = "DFN", 
        DepartmentCode = "DC" 
    };
}

和奖金 - 验证服务不会保存已经存在的部门:

[Test]
public void ShouldNotSaveExistingDepartment()
{
    mockUnitOfWork.Setup(u => u.Save()).Throws<NonUniqueEntityException>();
    var result = sut.SaveDepartment(CreateDepartment());
    Assert.False(result);
    mockUnitOfWork.VerifyAll();
}

如您所见,预期的行为很简单 - 当工作单元在部门保存期间抛出 NonUniqueEntityException 时,服务应返回 false。是的,我认为最好返回假。以下是使此测试通过的服务代码:

public bool SaveDepartment(Department department)
{
    try
    {
        repository.Add(department);
        _UoW.Save();
        return true;
    }
    catch (NonUniqueEntityException e)
    {
        // log exception
        return false;
    }            
}

首先删除多余的尝试...抓住。捕获异常只是为了重新引发它是没有意义的。就您在此处要求的测试而言,代码片段如下:

    [Test]
    public void ShouldSucessfully_SaveNewDepartment()
    {
        // Arrange
        var mockUnitOfWork = new Mock<IUnitOfWork>();
        var mockRepository = new Mock<IRepository<Department>>();
        Department newDept = new Department { CreatedOn = DateTime.Now, Status = true, DepartmentFullName = "DFN", DepartmentCode = "DC" };
        mockUnitOfWork.Setup(x => x.GetRepository<Department>()).Returns(mockRepository.Object);
        var sut = new DepartmentService(mockUnitOfWork.Object);
        // Act
        bool result = sut.SaveDepartment(newDept);
        // Assert 
        Assert.That(result, Is.True);
    }
   [Test]
    public void ShouldThrowExceptionWhenExceptionThrownInternally_SaveNewDepartment()
    {
        // Arrange
        var mockUnitOfWork = new Mock<IUnitOfWork>();
        var mockRepository = new Mock<IRepository<Department>>();
        mockUnitOfWork.Setup(x => x.GetRepository<Department>()).Returns(mockRepository.Object);
        mockUnitOfWork.Setup(uow => uow.Save()).Throws<Exception>();
        var sut = new DepartmentService(mockUnitOfWork.Object);
        // Act
        TestDelegate action = () => sut.SaveDepartment(new Department());
        // Assert 
        Assert.Throws<Exception>(action);
    }

我还想测试部门代码或部门全名何时为空,如果尝试保存,则应抛出异常。

这取决于您希望谁检查这些值:如果您想依靠数据库或工作单元来检查这些字段,这不是测试特定故障条件的夹具,而是您想要单元测试的装置。在这里,您应该只测试在uow引发异常的情况下会发生什么。

如果您计划在部门服务中添加这些检查,则可以执行以下操作:

[Test]
    public void ShouldThrowExceptionWhenDepartmentCodeIsNull_SaveNewDepartment()
    {
        // Arrange
        var mockUnitOfWork = new Mock<IUnitOfWork>();
        Department newDept = new Department
                                 {
                                     CreatedOn = DateTime.Now, 
                                     Status = true, DepartmentFullName = "DFN", 
                                     DepartmentCode = null
                                 };
        var sut = new DepartmentService(mockUnitOfWork.Object);
        // Act
        TestDelegate action = () => sut.SaveDepartment(newDept);
        // Assert 
        Assert.Throws<ArgumentException>(action);
    }

前提是您按如下方式修改了方法:

public bool SaveDepartment(Department newDepartment)
    {
        if (string.IsNullOrEmpty(newDepartment.DepartmentCode))
        {
            throw new ArgumentException("DepartmentCode must be not null");
        }
        repository.Add(newDepartment);
        _UoW.Save();
        return true;
    }