1

这是我的域类

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的方法。我无法为此编写单元测试。

我还想测试 DepartmentCode 或 DepartmentFullName 何时为空,如果尝试保存,则应引发异常。

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

[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 
    // ???
}
4

2 回答 2

0

首先删除多余的try...catch。捕获异常只是为了重新抛出它是没有意义的。至于你在这里要求的测试是片段:

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

我还想测试 DepartmentCode 或 DepartmentFullName 何时为空,如果尝试保存,则应引发异常。

这取决于您希望谁来检查这些值:如果您想依靠您的数据库或工作单元来检查这些字段,这不是测试特定故障条件的夹具,而是您想要一个单元测试。在这里,您应该只测试 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;
    }
于 2013-09-25T08:34:51.457 回答
0

首先 - 将所有常见的排列代码移动到 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,它还调用工作单元上的保存以提交数据。

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

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。是的,我认为最好返回false。这是使此测试通过的服务代码:

public bool SaveDepartment(Department department)
{
    try
    {
        repository.Add(department);
        _UoW.Save();
        return true;
    }
    catch (NonUniqueEntityException e)
    {
        // log exception
        return false;
    }            
}
于 2013-09-25T09:05:31.383 回答