C# 单元测试中的测试方法
我有如下C# 单元测试中的测试方法,c#,unit-testing,nunit,C#,Unit Testing,Nunit,我有如下服务。假设我想测试Create()方法。我在单元测试中读到,我应该通过比较、计数等方式进行测试。然后如何测试我的Create()方法。将返回类型从void Create更改为bool Create仅仅是为了能够检查方法输出以进行测试,这是丑陋的还是不理想的想法?你能提出一些建议吗 public class CreateCarService : ICreateCarService { private readonly ICarQuery _carQuery; private
服务
。假设我想测试Create()
方法。我在单元测试
中读到,我应该通过比较、计数等方式进行测试。然后如何测试我的Create()
方法。将返回类型从void Create
更改为bool Create
仅仅是为了能够检查方法输出以进行测试,这是丑陋的还是不理想的想法?你能提出一些建议吗
public class CreateCarService : ICreateCarService
{
private readonly ICarQuery _carQuery;
private readonly ICarRepository _carRepository;
public CreateCarService(ICarQuery carQuery, ICarRepository carRepository)
{
_carQuery = carQuery;
_carRepository = carRepository;
}
public void Create(Car car)
{
if (car == null) throw new CusException(Error, "Car object cannot be null");
if (_carQuery.IsLoginExist(car.Login))
throw new CusException(Error, "Message1");
if (_carQuery.IsEmailExist(car.Email))
throw new CusException(Error, "Message1");
_carRepository.Add(car);
}
}
您希望测试被测试成员的“预期行为”。由于被测成员不返回任何可验证的输出,并且依赖于外部抽象,因此您应该能够监视被测成员与该外部抽象的交互,并验证预期行为
一个这样的例子
public void CreateCarService_Create_Should_Add_Car() {
//Arrange
Car car = new Car {
Login = "Login",
Email = "Email"
};
ICarQuery carQuery = Mock.Of<ICarQuery>();
ICarRepository carRepository = Mock.Of<ICarRepository>();
ICreateCarService subject = new CreateCarService(carQuery, carRepository);
//Act
subject.Create(car);
//Assert
Mock.Get(carRepository).Verify(_ => _.Add(car), Times.Once);
}
public void CreateCarService\u Create\u应该\u Add\u Car(){
//安排
汽车{
Login=“Login”,
Email=“电子邮件”
};
ICarQuery carQuery=Mock.Of();
ICarRepository carRepository=Mock.Of();
ICreateCarService subject=新创建的CarService(carQuery、carRepository);
//表演
主题。创建(汽车);
//断言
Mock.Get(carRepository).Verify(=>u.Add(car),Times.one);
}
上面的示例安全地导航到被测试成员的末尾,但假设您想要测试针对null参数情况引发的异常
public void CreateCarService_Create_Should_Throw_CusException_For_Null_Car() {
//Arrange
ICreateCarService subject = new CreateCarService(null, null);
//Act
Action act = ()=> subject.Create(null);
//Assert
var ex = Assert.Throws<CusException>(act);
}
public void CreateCarService\u Create\u应该为\u Null\u Car()抛出\u CusException\u{
//安排
ICreateCarService subject=newcreatecarservice(null,null);
//表演
Action act=()=>subject.Create(空);
//断言
var ex=Assert.Throws(act);
}
您希望为通过被测成员的所有可能路径创建测试。因此,花些时间复习测试中的主题,并制定出可能的测试用例。安排受试者满足这些案例,并练习这些案例以验证预期行为
参考以更好地了解如何使用Moq模拟框架。您希望测试被测成员的“预期行为”。由于被测成员不返回任何可验证的输出,并且依赖于外部抽象,因此您应该能够监视被测成员与该外部抽象的交互,并验证预期行为
一个这样的例子
public void CreateCarService_Create_Should_Add_Car() {
//Arrange
Car car = new Car {
Login = "Login",
Email = "Email"
};
ICarQuery carQuery = Mock.Of<ICarQuery>();
ICarRepository carRepository = Mock.Of<ICarRepository>();
ICreateCarService subject = new CreateCarService(carQuery, carRepository);
//Act
subject.Create(car);
//Assert
Mock.Get(carRepository).Verify(_ => _.Add(car), Times.Once);
}
public void CreateCarService\u Create\u应该\u Add\u Car(){
//安排
汽车{
Login=“Login”,
Email=“电子邮件”
};
ICarQuery carQuery=Mock.Of();
ICarRepository carRepository=Mock.Of();
ICreateCarService subject=新创建的CarService(carQuery、carRepository);
//表演
主题。创建(汽车);
//断言
Mock.Get(carRepository).Verify(=>u.Add(car),Times.one);
}
上面的示例安全地导航到被测试成员的末尾,但假设您想要测试针对null参数情况引发的异常
public void CreateCarService_Create_Should_Throw_CusException_For_Null_Car() {
//Arrange
ICreateCarService subject = new CreateCarService(null, null);
//Act
Action act = ()=> subject.Create(null);
//Assert
var ex = Assert.Throws<CusException>(act);
}
public void CreateCarService\u Create\u应该为\u Null\u Car()抛出\u CusException\u{
//安排
ICreateCarService subject=newcreatecarservice(null,null);
//表演
Action act=()=>subject.Create(空);
//断言
var ex=Assert.Throws(act);
}
您希望为通过被测成员的所有可能路径创建测试。因此,花些时间复习测试中的主题,并制定出可能的测试用例。安排受试者满足这些案例,并练习这些案例以验证预期行为
参考以更好地理解如何使用Moq模拟框架。您可以通过使用方法设置IsLoginExist
和IsEmailExist
方法的Moq
行为来验证对于任何有效的Car
实例Add
方法只调用了一次
[TestFixture]
公开课考试
{
[测试]
public void CreateCarServiceTest()
{
var carQueryMock=new Mock();
var carRepositoryMock=新Mock();
var createCarService=new createCarService(carQueryMock.Object,carRepositoryMock.Object);
Setup(c=>c.IsLoginExist(It.IsAny())。返回(false);
Setup(c=>c.IsEmailExist(It.IsAny())。返回(false);
createCarService.Create(新车());
carRepositoryMock.Verify(c=>c.Add(It.IsAny()),Times.Once);
}
}
当Create
方法抛出异常时,检查否定情况也是有意义的
[测试]
公共无效CreateCarNegativeTest()
{
var carQueryMock=new Mock();
var carRepositoryMock=新Mock();
var createCarService=new createCarService(carQueryMock.Object,carRepositoryMock.Object);
抛出(()=>createCarService.Create(null));
Setup(c=>c.IsLoginExist(It.IsAny())。返回(true);
Assert.Throws(()=>createCarService.Create(newcar());
Setup(c=>c.IsLoginExist(It.IsAny())。返回(false);
Setup(c=>c.IsEmailExist(It.IsAny())。返回(true);
Assert.Throws(()=>createCarService.Create(newcar());
}
您可以将此方法拆分为不同的测试,以便每个测试都有一个断言
,或者将参数传递给它。您可以验证对于任何有效的Car
实例Add
方法只调用了一次,通过使用方法设置IsLoginExist
和IsEmailExist
方法的Moq
行为
[TestFixture]
公开课考试
{
[测试]
public void CreateCarServiceTest()
{
var carQueryMock=new Mock();
var carRepositoryMock=新Mock();
var createCarService=new createCarService(carQueryMock.Object,carRepositoryMock.Object);
Setup(c=>c.IsLoginExist(It.IsAny())。返回