【发布时间】:2018-02-01 19:52:07
【问题描述】:
我正在探索 TDD 和 SOLID 原则。假设我有一个服务,在编写实现之前我创建了一个失败的测试。
public interface IService {
bool DoSomething();
}
public class Service : IService {
bool DoSomething() {
...
}
}
[TestMethod]
public void ServiceImplementationTest()
{
var implementation = new Service();
bool result = implementation.DoSomething();
Assert.IsTrue(result);
}
当我第一次编写测试时,我不知道这个服务的依赖关系,所以构造函数不带参数,因为我不需要注入任何依赖关系。
但是,当我编写实现时,我意识到我需要某个依赖项,因此在构造函数中添加对该依赖项的引用。为了使测试代码保持编译和失败,然后我必须返回测试,并对其进行修改以创建一个假实现。
public class Service : IService {
public Service(IDependency dependency) {
_dependency = dependency;
}
bool DoSomething() {
... use _dependency ...
return result;
}
}
[TestMethod]
public void ServiceImplementationTest()
{
var implementation = new Service(*** new MockDependency() ***);
bool result = implementation.DoSomething();
Assert.IsTrue(result);
}
这只是生活中的事实吗?在编写测试之前我应该知道所有依赖项吗?当我想编写一个具有不同依赖关系的新实现时会发生什么,是否有必要为每个实现编写一个新的测试,即使实现的正确性没有改变?
【问题讨论】:
-
虽然是基于意见的,但依赖关系源于代码的重构。您不会总是事先知道。如果对被测主题的修改使某些测试不再相关,那么您可以简单地删除这些测试,否则需要模拟所需的依赖项。随着时间的推移,随着您的经验越来越丰富,您将倾向于找出可能需要哪些依赖项,并且在某些情况下可以事先知道可能需要哪些抽象。总而言之,这是红绿重构范式的一部分
-
不是您的问题的答案,但我发现 a variation of the Test Data Builder pattern 对于使测试夹具可维护非常有用。
标签: unit-testing dependency-injection mocking tdd solid-principles