我有一个单元测试,测试是否没有提供婴儿的名字,然后不保存婴儿,另一个如果提供了第一个名字,那么应该调用保存。我做了红色/绿色/重构,它通过了。我添加了新的测试,为姓做同样的事情。现在,名字的测试失败了,因为没有提供姓氏。我在下面提供了测试代码。我想知道我是否会以错误的方式解决这个问题,或者我只是希望纠正破损的测试?
此外,验证器接口是必需的,因为有效的更改取决于使用该软件的客户端,否则我会将这些检查编码到Baby类本身。
更新:根据我已经收到的一些回复,似乎我的方式错了。我应该做什么,以便不会出现这种情况?
[TestMethod]
public void baby_is_not_saved_if_validation_fails() {
// arange
var validator = new Mock<IValidator<Baby>>();
var output = new ValidationCollection();
validator.Setup(v => v.IsValid(It.IsAny<Baby>(), out output)).Returns(false);
var unitOfWork = GetMock();
// act
var b = new Baby();
var svc = new BabyService(validator.Object, unitOfWork.Object);
svc.AddNewBaby(b);
// assert
unitOfWork.Verify(u => u.SaveChanges(), Times.Never());
}
[TestMethod]
public void baby_is_saved_if_validation_passes() {
// arange
var validator = new Mock<IValidator<Baby>>();
var output = new ValidationCollection();
validator.Setup(v => v.IsValid(It.IsAny<Baby>(), out output)).Returns(true);
var unitOfWork = GetMock();
// act
var b = new Baby();
var svc = new BabyService(validator.Object, unitOfWork.Object);
svc.AddNewBaby(b);
// assert
unitOfWork.Verify(u => u.SaveChanges(), Times.Once());
}
[TestMethod]
public void if_first_name_is_not_supplied_baby_is_not_added() {
// arrange
var validator = new DefaultBabyValidator();
var unitOfWork = GetMock();
// act
var b = new Baby();
var svc = new BabyService(validator, unitOfWork.Object);
svc.AddNewBaby(b);
// assert
unitOfWork.Verify(u => u.SaveChanges(), Times.Never());
}
Mock<IHealthUnitOfWork> GetMock() {
var uow = new Mock<IHealthUnitOfWork>();
var dbSet = new Mock<IDbSet<Baby>>();
dbSet.Setup(db => db.Add(It.IsAny<Baby>())).Returns(new Baby());
uow.Setup(u => u.SaveChanges()).Verifiable();
uow.SetupGet(u => u.Babies).Returns(dbSet.Object);
return uow;
}
[TestMethod]
public void if_first_name_is_supplied_baby_is_added() {
// arrange
var validator = new DefaultBabyValidator();
var unitOfWork = GetMock();
// act
var b = new Baby { FirstName = "Charles" };
var svc = new BabyService(validator, unitOfWork.Object);
svc.AddNewBaby(b);
// assert
unitOfWork.Verify(u => u.SaveChanges(), Times.Once());
}
[TestMethod]
public void if_last_name_is_not_supplied_baby_is_not_added() {
// arrange
var validator = new DefaultBabyValidator();
var unitOfWork = GetMock();
// act
var b = new Baby { FirstName = "Charles" };
var svc = new BabyService(validator, unitOfWork.Object);
svc.AddNewBaby(b);
// assert
unitOfWork.Verify(u => u.SaveChanges(), Times.Never());
}
}
答案 0 :(得分:2)
您的问题是您的测试代表了相互矛盾的要求。如果提供了第一个名字而且姓氏不是,那么if_first_name_is_supplied_baby_is_added()表示应该保存宝宝,但是if_last_name_is_not_supplied_baby_is_not_added()表示宝宝不应该保存。
答案 1 :(得分:0)
问题在于,名字的原始测试当时没有姓氏的规格。当您的规格发生变化时,您的测试可能/将会发生变化。我已经重构了我的测试,因此我不需要在Baby类中发现新字段时更改以前的测试。我现在有一种测试方法可以确定有效婴儿的真实状况。现在,必要的现场测试检查以下内容:
现在我只需要在发现新字段时更新一个测试(所有字段都是有效的测试)。
[TestMethod] // only update this one as new fields are discovered
public void when_baby_is_valid_validation_returns_true() {
var validator = new DefaultBabyValidator();
// valid baby goes here
var baby = new Baby();
AggregateException fail;
Assert.IsTrue(validator.IsValid(baby, out fail));
}
[TestMethod]
public void validation_returns_exception_if_first_name_is_null() {
var validator = new DefaultBabyValidator();
AggregateException results;
var isValid = validator.IsValid(new Baby(), out results);
var expected = results.InnerExceptions
.OfType<ArgumentException>()
.SingleOrDefault(ex => ex.ParamName == "FirstName");
Assert.IsFalse(isValid); // should always return false if this condition is met
Assert.IsNotNull(expected); // should also contain the expected exception
}
[TestMethod]
public void validation_does_not_return_exception_if_first_name_is_valid() {
var validator = new DefaultBabyValidator();
AggregateException results;
validator.IsValid(new Baby { FirstName = "Charles" }, out results);
var expected = results.InnerExceptions
.OfType<ArgumentException>()
.SingleOrDefault(ex => ex.ParamName == "FirstName");
Assert.IsNull(expected); // exception should not exsist.
// We don't care if it returns true.
// There is only one case where IsValid should
// return true.
}