JUnit: new instance before invoking each @Test met

2019-01-15 18:00发布

Currently, I am reading "JUnit in action" book. In this book I found text below:

JUnit creates a new instance of the test class before invoking each @Test method. This helps provide independence between test methods and avoids unintentional side effects in the test code. Because each test method runs on a new test class instance, we can’t reuse instance variable values across test methods.

Now I do not see much point in this approach:

For example:

public class CalculatorTest {
    @Test
    public void testAdd_1() {
        Calculator calculator = new Calculator();
        double result = calculator.add(1, 1);
        assertEquals(2, result, 0);
    }

    @Test
    public void testAdd_2() {
        Calculator calculator = new Calculator();
        double result = calculator.add(2, 2);
        assertEquals(4, result, 0);
    }
}

For test class CalculatorTest there are no any benefits.

Ok, lets go pay attention on another example:

public class OneTest {

    static byte count;

    public OneTest() {
        count++;
    }

    @Test
    public void test1() {
        System.out.println(count);
    }

    @Test
    public void test2() {
        System.out.println(count);
    }
}

For test class OneTest I found a way to use the same variable count for the many test methods...

so, How to see the real benefits of the approach described in the book?

3条回答
对你真心纯属浪费
2楼-- · 2019-01-15 18:36

How to see the real benefits of the approach described in the book?

The purpose of separate instance is not for any benefit but to maintain the contract that each test should be independently executed without any effect of the execution of a previous test. There is just no other way to ensure this contract other than using a different instance for each test.

For example, the Spring transaction management makes sure to rollback all changes made to the database by a test, by default, to maintain the same contract.

So, using static variables in a test is generally discouraged as it will defeat the whole purpose of one-instance-per-test to have a clean slate for each test.

查看更多
一纸荒年 Trace。
3楼-- · 2019-01-15 18:42

Keeping the state clean between test methods is useful for unit tests but gets in the way for functional tests, where having dependencies between tests is often necessary (for example, when you are testing web pages using Selenium, it's useful to not bother running tests of a certain page if the tests for the login page failed).

This was one of the main reasons why I created TestNG, which doesn't instantiate a new class between each method, therefore giving you the choice instead of imposing this decision on you.

TestNG also supports dependencies of tests, multithread testing, has the notion of groups ("only run the servlet tests") and many more features.

查看更多
聊天终结者
4楼-- · 2019-01-15 18:56

If you're testing a mutable class, there's great value in having your tested object in a known state at the beginning of each test method, so that the order of test execution does not matter. The easiest way to accomplish that is to create a new instance of that class for each test, and to avoid static fields.

In your calculator example, it appears that your Calculator class is immutable and the results of method calls depend only on the parameters. So the risk of one test influencing another is just not there.

I don't quite see the point of your second example. You've written methods annotated as @Test that use a shared static field, but your methods have no assertions, and are not really testing anything.

If you want to do use static fields or indeed to hold onto and reuse a single instance of the class under test, it's certainly possible to to so, but to make your tests work and stay independent of each other will tend to require more care.

查看更多
登录 后发表回答