我试图为某些课程编写测试。我想测试的类使用不同的存储库来从数据库中获取和保存东西。
简化示例
library(plyr);library(dplyr)
library(googleVis)
df <- data.frame(Language = structure(c(rep("English",7), rep("German",5), rep("French", 10)), class = "character"),
Students = c(LETTERS[1:7], LETTERS[1:5], LETTERS[1:10]),
Start = structure(c(16713,16713,16713,16744,16713,16714,16754,16729,16729,16729,16750,16769,
16724,16724,16745,16724,16759,16766,16723,16722,16736,16796), class = "Date"),
End = structure(c(16762,16720,16762,16755,16720,16764,16762,16765,16765,16749,16761,16770,16758,
16744,16758,16764,16765,16766,16726,16723,16758,16806), class = "Date"))
ddply(df, .(Language), summarise,
FirstDay = min(Start),
LastDay = max(End),
Duration = LastDay - FirstDay)
plot(gvisTimeline(data=df, rowlabel = "Class", start = "Start", end = "End", options=list(width=600, height=1000) ))
我想要做的是确保保存到数据库中的内容是正确的。
所以我有这样的单元测试:
public class MyClass
{
private readonly IGroupRepository _groupRepo;
public MyClass(IGroupRepository groupRepo){
_groupRepo = groupRepo;
}
public void Execute(PersonInfo personInfo, string id){
var group = _groupRepo.GetById(id);
var person = group.Persons.First(p=> p.Id == personInfo.Id);
person.FirstName = personInfo.FirstName;
person.LastName = personInfo.LastName;
_groupRepo.Save(group);
}
}
我认为这很好,但后来我正在阅读更多内容并且我读到你不应该断言,我认为我在断言中做了什么?我从存根中获取信息,然后在结果上使用Assert?
所以我不确定这是否是正确的测试方法。如果没有,为什么以及正确的方法是什么?
答案 0 :(得分:1)
不建议您测试保存的内容 数据库是正确的。它更多的是集成测试而不是单元 测试,它超出了你的范围。
可能有很多原因导致数据无法在数据库中正确保存,但是您的类的行为应该是正常的,例如网络问题,但是失败的UT将不正确。
相反,您应该测试您的类,以了解数据库插入失败时类的行为方式,或者是否发生某些异常。然后使用您的模拟框架来模拟具有这些期望的存储库,并相应地在您的类的测试中断言。
答案 1 :(得分:1)
您不应该测试正在实施单元测试的类中使用的另一个模块/类的逻辑。
您应该只测试/验证是否正在调用对该模块的调用,正如您的业务逻辑所说的那样。您应该只关注该类的业务逻辑,仅用于编写单元测试用例。
在您的情况下,IGroupRepository是另一个模块/类,而不是您正在编写单元测试的模块/类。相反,如果您想验证数据是否正在保存,那么您应该将其包含在您为IGroupRepository实现的另一个测试用例中。
但是,不建议编写用于保存数据的单元测试,并将其视为集成测试的一部分。
答案 2 :(得分:1)
是的,你是对的,测试的编写方式有问题。实际上,您没有测试MyClass
。你正在测试那个
你使用的模拟框架是有效的。作为证明,请注释使用MyClass
的两行并再次运行测试。它仍然会通过:
[TestMethod]
public void TestMethod()
{
var groupId = "ABC";
var personId = 1;
ver personInfo = new PersonInfo()
{
Id = personId,
FirstName = "Sam",
LastName = "Smith" `
}
var groupStub = new Mock<IGroupRepository>;
groupStub.Setup(x=> x.GetById(groupId)).Returns(new Group(){
Id = groupId,
Persons = List<Person>()
{
new Person()
{
Id = personId,
FirstName = "George",
LastName = "Bolton",
}
}
}
});
// var myClass = new MyClass();
// myClass.Execute(personInfo, groupId);
var group = groupStub.GetById(groupId);
var person = group.Persons.First(p=> p.Id == personId);
Assert.AreEqual(personInfo.FirstName, person.FirstName);
}
通常帮助我编写单元测试,首先问自己我正在测试的行为。在这种特殊情况下,我相信你想在调用MyClass.Execute
时进行测试,
您希望在更改此人姓名的情况下调用IGroupRepository.Save
。
在我熟悉的(NSubstitute)模拟框架中写出这个断言,看起来像这样:
groupStub.Received().Save(
Arg.Is<Group>(group =>
{
return groupId.Id == groupId &&
group.Persons[0].Id == personId &&
group.Persons[0].FirstName == "Sam" &&
group.Persons[0].LastName == "Smith";
});
你使用的模拟框架中应该有类似的东西。