我正在尝试将测试添加到遗留代码中,当我开始添加代码时,我感觉有些问题。
在下面的代码中,公共方法RegisterChange正在调用两个私有方法:
public class ChangeService {
IRepository repository;
public ChangeService(IRepository repository){
this.repository = repository;
}
public bool RegisterChange( int entityId ){
var entity = GetParsedEntity( entityId );
SaveEntity( entity );
return true;
}
private Entity GetParsedEntity( int id ) {
var entity = repository.GetEntityById( id );
return new Entity{ Name = entity.Name };
}
private void SaveEntity( Entity entity ) {
repository.Save( Entity );
}
}
public class ChangeServiceFact(){
[Fact]
public void When_valid_entity__Should_save_entity(){
var mock = new Mock<IRepository>();
var service = new ChangeService(mock.object);
var result = service.RegisterChange( 0 );
Assert.True(result);
}
}
因此,当我嘲笑存储库时,我不得不去检查私有方法的代码以了解要模拟的操作。
我用这种方法看到的问题是,因为代码不仅测试测试主题(公共方法)而且还测试私有方法,不清楚哪个应该是测试结果,通过查看考试科目(公共方法)。
如果稍后某人决定修改一个私有方法(比如从GetParsedEntity抛出异常),则测试将继续正确传递,但客户端代码可能因此更改而失败。
在这种特殊情况下,我使用的是C#,XUnit和Moq,但我认为这更像是一个普遍的测试问题。
答案 0 :(得分:3)
我用这种方法看到的问题是,因为代码不仅测试测试主题(公共方法)而且还测试私有方法,不清楚哪个应该是测试结果,通过查看考试科目(公共方法)。
您提及的测试主题在不知道其完整合同的情况下没有明显效果。这里的完整合同是什么?提到的公共方法和构造函数,它具有依赖性。这是依赖,这是重要的,与这种依赖的交互是应该测试的。私有方法(一如既往)实现细节 - 与单元测试无关。
话虽如此,让我们回到合同中。测试对象的实际合同是什么(ChangeService
方法)?要基于某个id从存储库中检索对象,请创建不同的对象并将后者保存在同一个存储库中。这是你的考验。
[Fact]
public void ChangeService_StoresNewEntityInRepository_BasedOnProvidedId()
{
const string ExpectedName = "some name";
var otherEntity = new OtherEntity { Name = ExpectedName };
var mock = new Mock<IRepository>();
var service = new ChangeService(mock.object);
mock.Setup(m => m.GetEntityById(0)).Return(otherEntity);
service.RegisterChange(0);
mock.Verify(m => m.SaveEntity(It.Is<Entity>(e => e.Name == ExpectedName));
}