如何断言单元测试方法返回 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
// ???
}
首先 - 将所有常见的排列代码移动到 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;
}