单元测试架构问题

Tom*_*sky 15 java junit unit-testing

所以我开始为以下代码布局单元测试:

public interface MyInterface {
  void MyInterfaceMethod1();
  void MyInterfaceMethod2();
}

public class MyImplementation1 implements MyInterface {
  void MyInterfaceMethod1() {
    // do something
  }

  void MyInterfaceMethod2() {
    // do something else
  }

  void SubRoutineP() {
    // other functionality specific to this implementation
  }
}

public class MyImplementation2 implements MyInterface {
  void MyInterfaceMethod1() {
    // do a 3rd thing
  }

  void MyInterfaceMethod2() {
    // do something completely different
  }

  void SubRoutineQ() {
    // other functionality specific to this implementation
  }
}
Run Code Online (Sandbox Code Playgroud)

有几个实现和期望更多的未来.

我最初的想法是节省自己的时间重写单元测试用这样的东西:

public abstract class MyInterfaceTester {
  protected MyInterface m_object;  

  @Setup
  public void setUp() {
    m_object = getTestedImplementation();
  }

  public abstract MyInterface getTestedImplementation();

  @Test
  public void testMyInterfaceMethod1() {
    // use m_object to run tests
  }

  @Test
  public void testMyInterfaceMethod2() {
    // use m_object to run tests
  }
}
Run Code Online (Sandbox Code Playgroud)

然后,我可以轻松地子类化测试实现特定的附加方法,如下所示:

public class MyImplementation1Tester extends MyInterfaceTester {
  public MyInterface getTestedImplementation() {
    return new MyImplementation1();
  }

  @Test
  public void testSubRoutineP() {
    // use m_object to run tests
  }
}
Run Code Online (Sandbox Code Playgroud)

同样适用于2号以上的实施.

所以我的问题是:有什么理由不这样做吗?JUnit似乎很喜欢它,它满足了我的需求,但我在任何单元测试书和我一直在阅读的例子中都没有真正看到过这样的东西.

是否有一些我无意中违反的最佳做法?我是否会为自己的心痛做好准备?有没有更好的方法,我没有考虑过?

谢谢你的帮助.

S.L*_*ott 18

有什么理由不这样做吗?

不,这样做.测试是班正是这个原因.

我在任何单元测试书和我一直在阅读的例子中都没有真正看到过这样的东西.

继续阅读.介绍不包括此内容.

是否有一些我无意中违反的最佳做法?

没有.

我是否会为自己的心痛做好准备?

没有.

有些人对"脆弱测试"感到紧张.您可以在此处找到一些问题,寻找实现方法,以便对软件进行更改也不会导致测试更改.从长远来看,尝试创建"强大"测试是愚蠢的.您希望编写测试,以便软件的可见界面级别的每个小变化都需要测试重写.

您需要测试,以便不可见的内部更改不需要测试重写.

类和子类的使用与这些考虑正交.

有没有更好的方法,我没有考虑过?

不是.面向对象重点.出于这个原因,测试是一个类.


top*_*hef 5

虽然我支持SLott 100%,但我也会考虑JUnit参数化测试而不是测试类层次结构:

@RunWith(Parameterized.class)
public class MyInterfaceTester {
  private MyInterface m_object;  

  public void MyInterfaceTester(MyInterface object) {
    m_object = object;
  }

  @Parameters
  public static Collection<Object[]> data() {
    List<Object[]> list = new ArrayList<Object[]>();

    list.add(new Object[]{new MyImplementation1()});
    list.add(new Object[]{new MyImplementation2()});

    return list;
  }

  @Test
  public void testMyInterfaceMethod1() {
    // use m_object to run tests
  }

  @Test
  public void testMyInterfaceMethod2() {
    // use m_object to run tests
  }
}
Run Code Online (Sandbox Code Playgroud)

不需要测试类层次结构:只需通过在data方法中添加另一个列表元素来添加新实现.