单元测试体系结构问题

2022-09-03 13:16:33

因此,我开始为以下代码位布局单元测试:

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
  }
}

有几个实现,并期望更多。

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

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
  }
}

然后,我可以很容易地对其进行子类化以测试特定于实现的附加方法,如下所示:

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

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

同样适用于 Implmentation 2 以后。

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

我是否无意中违反了一些最佳实践?我是否在路上让自己心痛?有没有一种我没有考虑过的更好的方法?

感谢您的任何帮助。


答案 1

有什么理由不这样做吗?

不。做吧。正是出于这个原因,测试是类。

在我读过的任何单元测试书籍和示例中,我都没有真正看到过类似的东西。

继续阅读。介绍不包括这一点。

我是否无意中违反了一些最佳实践?

不。

我是否在路上让自己心痛?

不。

有些人对“脆性测试”感到紧张。您可以在这里找到一些问题,寻找实现它的方法,以便对软件的更改不会导致对测试的更改。从长远来看,试图创建“健壮”的测试是愚蠢的。您希望编写测试,以便对软件的可见界面级别的每个微小更改都需要重写测试。

您希望进行测试,以便不可见的内部更改不需要重写测试。

类和子类的使用与这些注意事项正交。

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

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


答案 2

虽然我支持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
  }
}

无需在测试类层次结构中:只需通过在方法中添加另一个列表元素来添加新的实现即可。data


推荐