在Junit测试中使用@Before

时间:2017-09-21 06:29:16

标签: java junit

需要在JUnit Testing中使用

@Before符号,因为多个测试需要在运行之前创建类似的对象。

但是,在测试用例函数作为全局对象之前实例化对象和放入@Before内部之间我没有区别。

例如,我正在测试我的国际象棋程序,我正在测试我的Piece对象是否移动到正确的位置:

public class PawnTest { //The Test Class itself

Board board = new Board();

@Test
/**
 * Testing the right movement
 */
public void correctMovementTest() {
    Pawn p1 = new Pawn(Player.UP);
    board.placePiece(4, 3, p1);
    board.movePieceTo(5, 3, p1);
    assertEquals(board.getPiece(5, 3), p1);
}

@Test
/**
 * Testing the right movement
 */
public void correctMovementTest2() {
    Pawn p1 = new Pawn(Player.UP);
    board.placePiece(4, 3, p1);
    board.movePieceTo(6, 3, p1);
    assertEquals(board.getPiece(6, 3), p1);
}

....

如果我在testcase方法之外转换BoardPawn p1,那么它是否会起作用?为什么我们在测试类中需要@Before

此外,这样做不会起作用

@Before
public void setup() {
    Board board = new Board();
    Pawn p1 = new Pawn(Player.UP);
}

我认为这实际上会在测试用例之前设置对象,这样我就不必在每个测试用例中设置它们,但是测试用例实际上并不会读取p1对象和板。

4 个答案:

答案 0 :(得分:5)

在您的类中执行每个测试用例之前,

@Before注释用于执行某些操作。所以,基本上你是在正确的方式。要使代码正常工作,您需要在功能范围之外声明BoardPawn

Board board = null;
Pawn p1 = null;

@Before
public void setup() {
    board = new Board();
    p1 = new Pawn(Player.UP);
}

在执行整个测试套件之前,还有@BeforeClass个注释可用于执行一些操作 - 例如启动嵌入式数据库。 希望它有所帮助!

答案 1 :(得分:1)

@Before@BeforeClass对于设置测试使用的外围设备非常有用。 @Before将在每次测试之前运行,而@BeforeClass将在测试套件之前运行(例如,在所有测试之前运行一次。)

让我们说你的测试都有一些常见的设置需要在运行之前完成。你可以总是只创建某种实用方法setup,然后在每个类之前手动调用它:

private void setup() {
  // do stuff
}

@Test
public void testFoo() {
  setup();
  // do test
}

@Test
public void testBar() {
  setup();
  // do test
}

...或者您可以使用setup注释@Before方法并让JUnit为您执行此操作:

@Before // JUnit will now call before every test, without you needing to do anything
public void setup() {
  // do stuff
}

@Test
public void testFoo() {
  // do test
}

@Test
public void testBar() {
  // do test
}

@BeforeClass注释在类似的概念下工作,除了它在整个套件之前挂钩并运行一次。

当我不得不模仿依赖时,我个人发现自己正在使用这些情况。

例如,考虑一个依赖于数据库连接的类。在我的@Before中,我将创建一个这个数据库连接的模拟实例,我的测试可以根据需要注入/使用它:

private DbConnector mockDb;

@Before
public void initMocks() {
  mockDb = Mockito.mock(DbConnector.class);
}

如果我不介意我的测试共享同一个实例,我可以mockDb静态并使用@BeforeClass

在您的特定情况下,您有Board个实例。如果您希望测试共享同一个板 - 例如,在给定板上运行不同测试没有副作用 - 那么您可以使用@BeforeClass创建新实例:

private static Board board;

@BeforeClass
public static void initBoard() {
  board = new Board();
  // other board init logic here
}

也许我们希望在任何地方共享相同的Board实例,但我们需要做一些清理或设置逻辑。然后我们可以使用@Before@After来注释这些方法,以便在每个测试实例周围运行它们,以使电路板进入预期状态。

@Before
public void setupBoard() {
  // setup logic, runs before each test (maybe puts the pieces where they should go for a new game?)
}

@After
public void resetBoard() {
  // reset logic, runs after every test (maybe remove scores, resets mocks, etc?)
}

何时使用这些注释,以及使用哪些特定的注释确实依赖于测试的设计方式。例如,如果设置您的主板只是new Board();而不是其他任何内容,那么您实际上并不需要@BeforeClass方法,而只能使用变量。

答案 2 :(得分:1)

从技术上讲,在测试类中包含实例字段(声明加初始化)以及在@Before方法中创建实例(仅将引用声明为实例字段)是相同的,即您的全局数据将可用于所有您的@Test方法,因为JUnit会自动为每个@Test方法运行创建一个测试类实例,因此@Before不需要始终

但是使用方法#1(声明加初始化都作为实例字段),您不必占用测试类实例创建和测试数据准备,同时保持关注点分离并根据阶段可视化过程是一个好主意,如, 创建测试类的实例 - >创建SUT实例(被测服务) - >准备SUT的测试数据 - >呼叫测试方法等...... (只是一个样本)。

@Before方法是使用模拟框架的必要条件,因为模拟需要首先在@Before方法中进行初始化,但这似乎不再是必需的。 See

您必须意识到,您提出的示例非常简单,而在企业应用程序中,要进行单元测试的类非常复杂,并且人们不希望通过测试数据准备来混淆其字段声明区域。

总而言之 - @Before并非强制性原因 - 即如果您希望在创建测试类实例之后执行某些操作(如果该用例非常适合您的方案),则使用它,否则您就是免费准备您的测试数据作为实例字段。

答案 3 :(得分:-1)

以下是一个例子:

带注释的方法@Before在每次调用@Test

之前运行

那么我要解决的问题是将局部变量转换为字段。这样,每个测试方法都可以访问变量。

 public class PawnTest { //The Test Class itself

 Board board;
 private Pawn p1;
@Before
public void setup() {
    board = new Board();
    p1 = new Pawn(Player.UP);
}


@Test
/**
 * Testing the right movement
 */
public void correctMovementTest() {
    board.placePiece(4, 3, p1);
    board.movePieceTo(5, 3, p1);
    assertEquals(board.getPiece(5, 3), p1);
}

@Test
/**
 * Testing the right movement
 */
public void correctMovementTest2() {
    board.placePiece(4, 3, p1);
    board.movePieceTo(6, 3, p1);
    assertEquals(board.getPiece(6, 3), p1);
}

@After
public void tearDown() {
    p1 = null;
    board = null;
}

添加拆卸,以便测试用例彼此独立。

编辑:将board初始化移至setUp()