参考: http://www.objectmentor.com/resources/articles/SelfShunPtrn.pdf
答案 0 :(得分:5)
我对此的看法是,测试类在技术上违反了SRP,但它并没有违反SRP的精神。自我分流的替代方法是将模拟类与测试类分开。
使用单独的模拟类,您可能会认为它全部是自包含的并且满足SRP,但是与模拟类的属性的语义耦合仍然存在。所以,实际上,我们没有实现任何有意义的分离。
以PDF为例:
public class ScannerTest extends TestCase implements Display
{
public ScannerTest (String name) {
super (name);
}
public void testScan () {
// pass self as a display
Scanner scanner = new Scanner (this);
// scan calls displayItem on its display
scanner.scan ();
assertEquals (new Item (“Cornflakes”), lastItem);
}
// impl. of Display.displayItem ()
void displayItem (Item item) {
lastItem = item;
}
private Item lastItem;
}
现在我们做一个模拟:
public class DisplayMock implements Display
{
// impl. of Display.displayItem ()
void displayItem (Item item) {
lastItem = item;
}
public Item getItem() {
return lastItem;
}
private Item lastItem;
}
public class ScannerTest extends TestCase
{
public ScannerTest (String name) {
super (name);
}
public void testScan () {
// pass self as a display
DisplayMock dispMock = new DisplayMock();
Scanner scanner = new Scanner (dispMock );
// scan calls displayItem on its display
scanner.scan ();
assertEquals (new Item (“Cornflakes”), dispMock.GetItem());
}
}
实际上(恕我直言)TestClass
与DisplayMock
的较高耦合比违反TestClass
的SRP更为邪恶。此外,使用模拟框架,这个问题完全消失了。
编辑我刚刚在Robert C. Martin的优秀书籍Agile Principles, Patterns, and Practices in C#中简要提到了自我分流模式。以下是本书的摘录:
因此,创造SRP的人(在同一本书中详细讨论过)并没有使用自分流模式的疑虑。有鉴于此,我会说在使用这种模式时你对OOP(Objected Orientated Police)非常安全。
答案 1 :(得分:3)
在我看来,是违规行为,但非常轻微。
您测试类现在是测试类和依赖于您正在测试的任何内容。
然而,这是件坏事吗?对于几个简单的测试,可能不是。随着您的测试用例数量的增加,您可能希望重构并使用模拟类来分离一些问题。 (正如你粘贴的链接所说,自我分流是嘲弄的敲门砖)。但是,如果测试用例的数量保持静态和低,那么问题是什么?我认为需要一点实用主义。它违反了SRP吗?是的,但我猜可能不像你正在测试的系统中的一些代码那么多。你需要做些什么吗?不,只要代码清晰可维护,这对我来说总是最重要的。 SRP是一个指导原则,而非规则。
答案 2 :(得分:1)
如果更改了实现或分流的界面,则测试套件也必须更改。所以我并不认为它违反了SRP。
答案 3 :(得分:1)
我更喜欢对我正在创建的模拟/存根进行更多控制。当我尝试使用自分流模式时,我最终使我的测试类更加复杂。通过在测试方法中将模拟作为本地创建,我最终得到了更清晰的代码。
除非您使用像C#(或python或同等版本)这样的强大功能,否则您的测试代码将在您更改界面时发生变化。