简体   繁体   English

如何在JUnit测试用例中避免继承?

[英]How to avoid inheritance in JUnit test cases?

I have a number of test cases in JUnit. 我在JUnit中有很多测试用例。 All of them need the same code to be executed in their @BeforeClass static method. 所有这些都需要在@BeforeClass静态方法中执行相同的代码。 It's a code duplication and I'm trying to get rid of it. 这是一个代码重复,我试图摆脱它。 A dirty way of doing this is by inheritance. 这样做的一种肮脏方式是继承。 Are there any other mechanisms in JUnit, that may help? JUnit中是否还有其他机制可能会有所帮助?

PS. PS。 I wrote this blog post about this very subject: http://www.yegor256.com/2015/05/25/unit-test-scaffolding.html 我写了这篇关于这个主题的博客文章: http//www.yegor256.com/2015/05/25/unit-test-scaffolding.html

The JUnit way to compose reusable code (instead of inheriting from it) are Rules. 构建可重用代码(而不是从中继承)的JUnit方法是规则。

See https://github.com/junit-team/junit/wiki/Rules 请参阅https://github.com/junit-team/junit/wiki/Rules

Here is a dumb sample, but you'll get the point. 这是一个愚蠢的样本,但你会明白这一点。

import org.junit.rules.TestRule;
import org.junit.runners.model.Statement;
import org.junit.runner.Description;

public class MyTestRule implements TestRule {
  @Override
  public Statement apply(final Statement statement, Description description) {
    return new Statement() {
      public void evaluate() throws Throwable {
        // Here is BEFORE_CODE
        try {
          statement.evaluate();
        } finally {
          // Here is AFTER_CODE
        }
      }
    };
  }
}

You can then use your TestRule like this: 然后,您可以像这样使用TestRule:

import org.junit.Rule;

public class MyTest {
    @Rule
    public MyTestRule myRule = new MyTestRule();
}

BEFORE_CODE and AFTER_CODE will then be executed around each of your test methods. 然后将围绕每个测试方法执行BEFORE_CODE和AFTER_CODE。

If you need to run your code only once per class, use your TestRule as a @ClassRule: 如果您只需要为每个类运行一次代码,请将TestRule用作@ClassRule:

import org.junit.ClassRule;

public class MyTest {
    @ClassRule
    public static MyTestRule myRule = new MyTestRule();
}

Now, BEFORE_CODE and AFTER_CODE will be executed around each of your test class. 现在, BEFORE_CODEAFTER_CODE将在每个测试类周围执行。

@Rule field is not static, @ClassRule field is. @Rule字段不是静态的, @ ClassRule字段是。

A @ClassRule can be declared in a Suite too. @ClassRule也可以在套件中声明。

Note that you can declare several rules in a single test class, that's how you compose test lifecycles at test-suites, test-classes and test-methods levels. 请注意,您可以在单个测试类中声明多个规则,这就是在测试套件,测试类和测试方法级别组成测试生命周期的方式。

A Rule is an object that you instanciate in your test classes (statically or not). 规则是您在测试类中实例化的对象(静态或非静态)。 You can add contructor parameters if needed. 如果需要,您可以添加构造函数参数。

HTH HTH

If the method is some kind of utility, then separate it out to a different class with a static method and call that method in your @BeforeClass. 如果该方法是某种实用程序,则使用静态方法将其分离到不同的类,并在@BeforeClass中调用该方法。

I emphasize on the fact that don't use inheritance just because it solves your problem, use it when doing so creates sense in your class hierarchy. 我强调的是,不要仅仅因为它解决了你的问题而使用继承,在这样做时使用它会在你的类层次结构中产生意义。

You may create test runner 您可以创建测试运行器

public class MyTestRunner extends BlockJUnit4ClassRunner {
  @Override
  protected Object createTest() throws Exception {
     Object test = super.createTest();
     doStuff();
  }

  public void doStuff(){
     //common code
  }
}


@RunWith(MyTestRunner.class)
public class MyTest1{
    @Test
    public void test1(){
      //test method
    }
}

Static methods aren't inherited, so inheritance isn't an option by default. 静态方法不是继承的,因此默认情况下继承不是一个选项。 If you mean you're moving the method to a common parent class, then that seems a poor choice since you only get one parent in Java. 如果你的意思是你正在将方法移动到一个公共父类,那么这似乎是一个糟糕的选择,因为你只能在Java中获得一个父类。 A test support class of some sort would seem more appropriate. 某种测试支持类似乎更合适。 It's also possible that you're seeing a need for a parameterized test . 您也可能需要进行参数化测试

There is absolutely nothing wrong with inheritance in this case, it's actually the only way to avoid repeating this code in each subclass. 在这种情况下,继承绝对没有错,它实际上是避免在每个子类中重复此代码的唯一方法。 The fact that @BeforeClass methods have to be declared static in JUnit is unfortunate, but that shouldn't stop you. 必须在JUnit中将@BeforeClass方法声明为静态这一事实是不幸的,但这不应该阻止你。 Extend the class and you have the initialization code automatically run for you without having to do anything. 扩展类,您可以自动为您运行初始化代码,而无需执行任何操作。

If each and every class needs to have a @BeforeClass annotated method that is exactly the same as every other, then inheritance does not feel that wrong to me. 如果每个类都需要有一个@BeforeClass标注的方法是完全一样的,因为每个其他,然后继承不觉得我错了。 If each of these initializing methods simply share some code, you could make a TestUtil class with some shared behavior and make calls to this shared behavior from each of the @BeforeClass methods. 如果这些初始化方法中的每一个只是共享一些代码,那么可以使TestUtil类具有一些共享行为,并从每个@BeforeClass方法调用此共享行为。

I think if the classes has "is-a" relation, inheritance is reasonable. 我认为如果类具有“is-a”关系,则继承是合理的。

If the base class is MyBeforeClass which defines @BeforeClass method, and MyTestClass1 "is-a" MyBeforeClass , MyTestClass1 extends MyBeforeClass is OK. 如果基类是定义@BeforeClass方法的MyBeforeClass ,而MyTestClass1 “是MyBeforeClassMyBeforeClass ,则MyTestClass1 extends MyBeforeClass就可以了。

Depending on the nature of the setup code, you can potentially put all your tests in a test suite and have the setup code run there. 根据设置代码的性质,您可以将所有测试放在测试套件中 ,并在那里运行设置代码。 The downside to this is that you cannot run tests individually (since the test depends on the setup code). 这样做的缺点是您无法单独运行测试(因为测试取决于设置代码)。

It is test code , and it is not meant for heavy re-use. 它是测试代码 ,并不意味着重复使用。 Do not over-engineer. 不要过度工程。 Do not apply all the design patterns that you know. 不要应用您知道的所有设计模式。 For test code , the rules are different. 对于测试代码 ,规则是不同的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM