当单元测试调用其他类的类时,我总是遇到问题,例如,我有一个类,它从电话号码创建一个新用户,然后将其保存到数据库,并向提供的号码发送短信。
与下面提供的代码一样。
public class UserRegistrationProcess : IUserRegistration
{
private readonly IRepository _repository;
private readonly ISmsService _smsService;
public UserRegistrationProcess(IRepository repository, ISmsService smsService)
{
_repository = repository;
_smsService = smsService;
}
public void Register(string phone)
{
var user = new User(phone);
_repository.Save(user);
_smsService.Send(phone, "Welcome", "Message!");
}
}
这是一个非常简单的课程,但你会如何进行测试呢?
目前我正在使用Mocks,但我真的不喜欢它
[Test]
public void WhenRegistreringANewUser_TheNewUserIsSavedToTheDatabase()
{
var repository = new Mock<IRepository>();
var smsService = new Mock<ISmsService>();
var userRegistration = new UserRegistrationProcess(repository.Object, smsService.Object);
var phone = "07012345678";
userRegistration.Register(phone);
repository.Verify(x => x.Save(It.Is<User>(user => user.Phone == phone)), Times.Once());
}
[Test]
public void WhenRegistreringANewUser_ItWillSendANewSms()
{
var repository = new Mock<IRepository>();
var smsService = new Mock<ISmsService>();
var userRegistration = new UserRegistrationProcess(repository.Object, smsService.Object);
var phone = "07012345678";
userRegistration.Register(phone);
smsService.Verify(x => x.Send(phone, It.IsAny<string>(), It.IsAny<string>()), Times.Once());
}
感觉我在这里测试错误的东西?
关于如何做到这一点的任何想法?
答案 0 :(得分:4)
以@Serghei建议的方式重构模拟是好的。
我还看到行为的名称实际上并没有描述行为。我喜欢使用“应该”这个词,如“我的班级should do some stuff
”。
您的班级在注册用户时不应将用户发送到数据库。它应该要求存储库保存用户。就这样。它不知道存储库是将其发送到数据库,将其保存在内存中还是从轨道上进行核对。这不是你班级的责任。
通过这种方式表达行为,你可以明确地表明 - 并帮助他人理解 - 你的职责范围在哪里结束。
如果您将方法重命名为WhenRegisteringANewUser_AsksRepositoryToSaveIt()
,可能会让您感觉更自然。
答案 1 :(得分:0)
在你的情况下,不需要写
repository.Verify(x => x.Save(It.Is<User>(user => user.Phone == phone)), Times.Once());
因为此方法不返回值 你可以写
repository.VerifyAll();
对于smsService,这是使用Moq的好方法。
答案 2 :(得分:0)
看看一些重构
Mock<IRepository<>> repository;
private Mock<ISmsService> smsService;
const string phone = "0768524440";
[SetUp]
public void SetUp()
{
repository = new Mock<IRepository<>>();
smsService = new Mock<ISmsService>();
}
[Test]
public void WhenRegistreringANewUser_TheNewUserIsSavedToTheDatabase()
{
var userRegistration = new UserRegistrationProcess(repository.Object, smsService.Object);
userRegistration.Register(phone);
repository.VerifyAll();
smsService.VerifyAll();
}