我正在探索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);
}
这只是生活中的一个事实吗?在编写测试之前我应该知道所有依赖项吗?当我想编写一个具有不同依赖关系的新实现时会发生什么,是否有必要为每个实现编写一个新的测试,即使实现的正确性没有改变?
答案 0 :(得分:4)
您是否应该事先知道每个测试的依赖性
不一定,没有。
当你设计"先测试时,你在做什么"是你正在探索一个可能的API。所以下面的代码
var implementation = new Service();
bool result = implementation.DoSomething();
Assert.IsTrue(result);
除其他事项外,表示 public API 应该允许您创建Service
的实例,而不了解其依赖关系。
但是,当我编写实现时,我意识到我需要一个特定的依赖项,因此在构造函数中添加对该依赖项的引用。为了保持测试代码的编译和失败,我必须回到测试,并修改它以创建一个虚假的实现。
请注意这里的两件事
因此,部分问题在于您以向后不兼容的方式介绍所需的更改。如果你是重构,你将有一个步骤,你的构造函数看起来像
public Service() {
this(new IDependency() {
// default IDependencyImplementation here
});
}
Service(IDependency dependency) {
this.dependency = dependency;
}
此时,您有两个独立的决定
Service(IDependency)
成为公共API的一部分如果是这样,那么你开始编写强制你公开构造函数的测试
Service()
如果它应该,那么当您从公共API中删除Service()
时,您计划删除依赖它的测试。
注意:如果您还没有共享/发布公共API,那么这是很多不必要的步骤。除非您故意采用校准测试不可变的规则,否则通常更实际的是破解测试以反映最新的API草案。
但是,不要忘记在更改之后重新校准测试;对测试的任何更改都必须触发刷新红/绿循环,以确保修订后的测试仍在测量您的预期。您永远不应该发布您尚未校准的测试。有时有用的模式是将被测系统的组成与自动检查分开
public void ServiceImplementationTest()
{
var implementation = new Service();
check(implementation);
}
void check(Service implementation) {
bool result = implementation.DoSomething();
Assert.IsTrue(result);
}
另一种选择是写一个spike - 一个没有测试的可能实现的草案,目的是探索更好地理解问题的约束,当它被抛弃时学习练习已经完成。
您能快速描述测试校准的含义吗?谷歌并没有多大帮助。是否确保测试失败?
是的:确保失败时应该这样做,确保他们做失败时报告的消息是合适的,当然也要确保他们应该通过。
我写了一些关于here的想法。