这是我的域类
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
// ???
}
答案 0 :(得分: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;
}
答案 1 :(得分: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,它还会调用保存工作单元来提交数据。
BTW如上所示,我使用辅助方法使测试更加干净:
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;
}
}