Подтвердить что ты не робот

Junit - несколько @Before против одного @перед разделением на методы

В unit test мне нужно выполнить довольно сложную настройку (это может быть запах кода, но это не тот вопрос, о котором идет речь:-)). Я заинтересован в том, что лучше иметь несколько методов @Before, выполняющих установку, или только один, который вызывает вспомогательные методы для выполнения инициализации.

например.

@Before
public void setUpClientStub() {

}

@Before
public void setUpObjectUnderTest() {

}

против.

@Before
public void setUp() {
    setUpClientStub();
    setUpObjectUnderTest();
}
4b9b3361

Ответ 1

Как было сказано в других ответах, порядок, в котором JUnit находит методы, не гарантируется, поэтому порядок @Before методов @Before не может быть гарантирован. То же самое относится к @Rule, он страдает от такой же гарантии. Если это всегда будет один и тот же код, тогда нет никакой разницы в двух методах.

Если у вас есть два метода, и что более важно, если вы хотите использовать их из нескольких мест, тогда вы можете комбинировать правила, используя RuleChain, который был введен в 4.10. Это позволяет задать порядок правил, например:

public static class UseRuleChain {
  @Rule
  public TestRule chain= RuleChain
               .outerRule(new LoggingRule("outer rule"))
               .around(new LoggingRule("middle rule"))
               .around(new LoggingRule("inner rule"));

  @Test
  public void example() {
      assertTrue(true);
  }
}

Это дает:

starting outer rule
starting middle rule
starting inner rule
finished inner rule
finished middle rule
finished outer rule

Таким образом, вы можете либо перейти на 4.10, либо просто украсть класс.

В вашем случае вы можете определить два правила: один для настройки клиента и один для объекта, и объединить их в RuleChain. Использование ExternalResource.

public static class UsesExternalResource {
  private TestRule clientRule = new ExternalResource() {
      @Override
      protected void before() throws Throwable {
        setupClientCode();
      };

      @Override
      protected void after() {
        tearDownClientCode()
    };
  };

  @Rule public TestRule chain = RuleChain
                   .outerRule(clientRule)
                   .around(objectRule);
}

Таким образом, у вас будет следующий порядок выполнения:

clientRule.before()
objectRule.before()
the test
objectRule.after()
clientRule.after()

Ответ 2

Я бы сделал последнее. AFAIK, нет способа гарантировать порядок @Before аннотированных методов настройки.

Ответ 3

Обратите внимание, что нет никаких гарантий относительно порядка, в котором вызывается @Before аннотированные методы. Если между ними есть некоторые зависимости (например, один метод должен быть вызван перед другим), вы должны использовать последнюю форму.

В противном случае это вопрос предпочтения, просто держите их в одном месте, чтобы их было легко обнаружить.

Ответ 4

Я не думаю, что это имеет большое значение, но я лично предпочитаю второй (порядок до того, как методы выполняются не определены, у вас будет лучший контроль таким образом).

Ответ 5

Для меня это похоже на использование JUnit 4.12, методы, аннотированные с помощью @Before действительно детерминистически сортируются по следующему @Before:

путем обратного лексикографического порядка относительно имени метода.

Вы можете увидеть это поведение, выполнив этот Testclass:

import java.util.Arrays;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

/*
 * key points:
 * - multiple @Before methods get sorted by reversed lexicographic order 
 * */
public class JUnitLifecyle {

    @BeforeClass
    public static void runsOnceBeforeClassIsInited() {
        System.out.println("@BeforeClass");
    }

    public JUnitLifecyle() {
        System.out.println("Constructor");
    }

    @Before
    public void a() {
        System.out.println("@Before a");
    }

    @Before
    public void b() {
        System.out.println("@Before b");
    }

    @Before
    public void cd() {
        System.out.println("@Before cd");
    }

    @Before
    public void ca() {
        System.out.println("@Before ca");
    }

    @Before
    public void cc() {
        System.out.println("@Before cc");
    }

    @Before
    public void d() {
        System.out.println("@Before d");
    }

    @Before
    public void e() {
        System.out.println("@Before e");
    }

    @Test
    public void firstTest() {
        System.out.println("@Test 1");
    }

    @Test
    public void secondTest() {
        System.out.println("@Test 2");
    }

    @After
    public void runsAfterEveryTestMethod() {
        System.out.println("@After");
    }

    @AfterClass
    public static void runsOnceAfterClass() {
        System.out.println("@AfterClass");
    }
}

Я пришел к такому выводу после игры с выходом, изменяя имена методов методов, аннотированных с помощью @Before.

Помня об этом обратном лексикографическом порядке, вы могли бы назвать свои методы соответствующим образом, чтобы JUnit выполнил ваши задачи настройки в правильном порядке.

Хотя вышеупомянутый подход возможен, я думаю, вы не должны делать этого в своих тестах, потому что Java-Annotations в JUnit была введена, чтобы уйти от тестирования на основе конвенций.