自分流测试模式是否违反单一责任原则?

时间:2010-08-17 02:46:14

标签: unit-testing design-patterns oop

多年来,我多次使用自分流单元测试模式。正如我最近向某人解释的那样,他们认为它违反了SRP。参数是现在可以出于以下两个原因之一更改测试类:测试更改时,或者测试正在实现的接口上的方法签名发生更改时。在考虑了一段时间后,似乎这是一个正确的评估,但我想得到其他人的意见。想法?

参考: http://www.objectmentor.com/resources/articles/SelfShunPtrn.pdf

4 个答案:

答案 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());
  }
}

实际上(恕我直言)TestClassDisplayMock的较高耦合比违反TestClass的SRP更为邪恶。此外,使用模拟框架,这个问题完全消失了。

编辑我刚刚在Robert C. Martin的优秀书籍Agile Principles, Patterns, and Practices in C#中简要提到了自我分流模式。以下是本书的摘录:

alt text

因此,创造SRP的人(在同一本书中详细讨论过)并没有使用自分流模式的疑虑。有鉴于此,我会说在使用这种模式时你对OOP(Objected Orientated Police)非常安全。

答案 1 :(得分:3)

在我看来,违规行为,但非常轻微。

您测试类现在是测试类依赖于您正在测试的任何内容。

然而,这是件坏事吗?对于几个简单的测试,可能不是。随着您的测试用例数量的增加,您可能希望重构并使用模拟类来分离一些问题。 (正如你粘贴的链接所说,自我分流是嘲弄的敲门砖)。但是,如果测试用例的数量保持静态和低,那么问题是什么?

我认为需要一点实用主义。它违反了SRP吗?是的,但我猜可能不像你正在测试的系统中的一些代码那么多。你需要做些什么吗?不,只要代码清晰可维护,这对我来说总是最重要的。 SRP是一个指导原则,而非规则。

答案 2 :(得分:1)

如果更改了实现或分流的界面,则测试套件也必须更改。所以我并不认为它违反了SRP。

答案 3 :(得分:1)

我更喜欢对我正在创建的模拟/存根进行更多控制。当我尝试使用自分流模式时,我最终使我的测试类更加复杂。通过在测试方法中将模拟作为本地创建,我最终得到了更清晰的代码。

除非您使用像C#(或python或同等版本)这样的强大功能,否则您的测试代码将在您更改界面时发生变化。