JUnit nhầm lẫn: sử dụng 'mở rộng TestCase' hoặc '@Test'?


152

Tôi đã thấy việc sử dụng đúng (hoặc ít nhất là tài liệu) của JUnit rất khó hiểu. Câu hỏi này phục vụ cả như một tài liệu tham khảo trong tương lai và như một câu hỏi thực sự.

Nếu tôi hiểu đúng, có hai cách tiếp cận chính để tạo và chạy thử nghiệm JUnit:

Cách tiếp cận A (kiểu JUnit 3): tạo một lớp mở rộng TestCase và bắt đầu các phương thức thử nghiệm với từ này test. Khi chạy lớp dưới dạng Kiểm tra JUnit (trong Eclipse), tất cả các phương thức bắt đầu bằng từ testnày sẽ tự động chạy.

import junit.framework.TestCase;

public class DummyTestA extends TestCase {

    public void testSum() {
        int a = 5;
        int b = 10;
        int result = a + b;
        assertEquals(15, result);
    }
}

Cách tiếp cận B (kiểu JUnit 4): tạo một lớp 'bình thường' và thêm một @Testchú thích cho phương thức. Lưu ý rằng bạn KHÔNG phải bắt đầu phương thức với từ này test.

import org.junit.*;
import static org.junit.Assert.*;

public class DummyTestB {

    @Test
    public void Sum() {
        int a = 5;
        int b = 10;
        int result = a + b;
        assertEquals(15, result);
    }
}

Trộn cả hai dường như không phải là một ý tưởng hay, xem ví dụ câu hỏi stackoverflow này :

Bây giờ, câu hỏi của tôi:

  1. Cách tiếp cận ưa thích là gì , hoặc khi nào bạn sẽ sử dụng phương pháp này thay vì phương pháp khác?
  2. Cách tiếp cận B cho phép kiểm tra các trường hợp ngoại lệ bằng cách mở rộng chú thích @Test như trong @Test(expected = ArithmeticException.class). Nhưng làm thế nào để bạn kiểm tra các trường hợp ngoại lệ khi sử dụng phương pháp A?
  3. Khi sử dụng phương pháp A, bạn có thể nhóm một số lớp kiểm tra trong bộ kiểm tra như thế này:

    TestSuite suite = new TestSuite("All tests");
    suite.addTestSuite(DummyTestA.class);
    suite.addTestSuite(DummyTestAbis.class);

    Nhưng điều này không thể được sử dụng với cách tiếp cận B (vì mỗi lớp thử nghiệm nên phân lớp TestCase). Cách thích hợp để kiểm tra nhóm cho phương pháp B là gì?

Chỉnh sửa: Tôi đã thêm các phiên bản JUnit cho cả hai phương pháp


Tôi đã xem extends TestCasevà sau đó mỗi bài kiểm tra cũng được chú thích @Testchỉ để gây nhầm lẫn. :)
EM-Creations

Câu trả lời:


119

Việc phân biệt khá dễ dàng:

  • mở rộng TestCaselà cách các bài kiểm tra đơn vị được viết trong JUnit 3 (tất nhiên nó vẫn được hỗ trợ trong JUnit 4)
  • sử dụng @Testchú thích là cách được giới thiệu bởi JUnit 4

Nói chung, bạn nên chọn đường dẫn chú thích, trừ khi khả năng tương thích với JUnit 3 (và / hoặc phiên bản Java sớm hơn Java 5) là cần thiết. Cách mới có một số lợi thế:

  • Các @Testannotaton là rõ ràng hơn và dễ dàng hơn để hỗ trợ trong các công cụ (ví dụ thật dễ dàng để tìm kiếm tất cả các bài kiểm tra theo cách này)
  • Nhiều phương thức có thể được chú thích bằng @Before/ @BeforeClass@After/ @AfterClasscung cấp sự linh hoạt hơn
  • Hỗ trợ các @Rulechú thích về những thứ nhưExpectedException
  • Hỗ trợ @Ignoredchú thích
  • Hỗ trợ cho người chạy thử nghiệm thay thế bằng cách sử dụng @RunWith

Để kiểm tra các trường hợp ngoại lệ dự kiến ​​trong JUnit 3, TestCasebạn phải làm cho văn bản rõ ràng.

public void testMyException() {
  try {
    objectUnderTest.myMethod(EVIL_ARGUMENT);
    fail("myMethod did not throw an Exception!");
  } catch (MyException e) {
    // ok!
    // check for properties of exception here, if desired
  }
}

JUnit 5 đã giới thiệu một thay đổi API khác, nhưng vẫn sử dụng các chú thích. @TestChú thích mới là org.junit.jupiter.api.Test(JUnit 4 "cũ" org.junit.Test), nhưng nó hoạt động khá giống với JUnit 4 một.


Câu trả lời hữu ích và kỹ lưỡng, nhưng tôi không hiểu đầy đủ "kiểm tra tin nhắn ngoại lệ". Kiểm tra đối với một chuỗi mã hóa cứng sẽ là một cơn ác mộng bảo trì. Bạn phải có nghĩa là "kiểm tra các thuộc tính của loại ngoại lệ cụ thể của bạn".
thSoft

3
@thSoft: chẳng hạn như nó thường được sử dụng, nhưng đôi khi tôi muốn chắc chắn rằng phương pháp ngoại lệ đề cập đến trường vi phạm chẳng hạn. Sau đó, một đơn giản assertTrue(e.getMessage().contains("foo"))có thể hữu ích.
Joachim Sauer

1
Ngay cả trong JUnit4, đây là một thành ngữ quan trọng khi bạn phải kiểm tra tin nhắn hoặc một số thuộc tính khác của ngoại lệ (chẳng hạn như nguyên nhân). Các expectedphương pháp duy nhất kiểm tra các loại.
Yishai

@Yishai: điều đó đúng, nhưng hầu hết thời gian tôi đã hài lòng nếu phương thức ném đúng loại Ngoại lệ vào đầu vào có vấn đề.
Joachim Sauer

Vì lý do đó, JUnit 5 đã thực hiện một thay đổi đột phá trong thử nghiệm ngoại lệ. assertThrows () thật tuyệt vời :-)
Marcus K.

25

Tôi có một ưu tiên cho JUnit 4 (Cách tiếp cận chú thích) vì tôi thấy nó linh hoạt hơn.

Nếu bạn muốn xây dựng bộ thử nghiệm trong JUnit 4, bạn phải tạo một nhóm nhóm tất cả các thử nghiệm như thế này:

import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;


@RunWith(Suite.class)
@SuiteClasses({
    Test1.class,
    Test2.class,
    Test3.class,
    Test4.class
})public class TestSuite
{
 /* empty class */
}

15

Có một phần chưa được trả lời cho câu hỏi của bạn và đó là "Cách thích hợp để nhóm kiểm tra cho phương pháp B là gì?"

Câu trả lời chính thức là bạn chú thích một lớp với @RunWith (Suite. Class) và sau đó sử dụng chú thích @ Suite.SuiteC Cầu để liệt kê các lớp. Đây là cách các nhà phát triển JUnit làm điều đó (liệt kê mọi lớp trong một bộ theo cách thủ công). Theo nhiều cách, cách tiếp cận này là một sự cải tiến, trong đó việc bổ sung trước và sau các hành vi của bộ phần mềm là rất đơn giản và trực quan (chỉ cần thêm phương thức @B BeforeClass và @AfterClass vào lớp được chú thích bằng @RunWith - tốt hơn nhiều so với TestFixture cũ ).

Tuy nhiên, nó có một bước lùi, trong đó các chú thích không cho phép bạn tự động tạo danh sách các lớp và làm việc xung quanh vấn đề đó trở nên hơi xấu. Bạn phải phân lớp lớp Suite và tự động tạo mảng các lớp trong lớp con và chuyển nó đến hàm tạo của Suite, nhưng đây là một giải pháp không hoàn chỉnh trong các lớp con khác của Suite (như Danh mục) không hoạt động với nó và về cơ bản không hỗ trợ bộ sưu tập lớp Test động.


1
+1 cho điều này. Sau khi bắt tay vào một nhiệm vụ để viết một giải pháp động để thêm các Bài kiểm tra vào TestSuite, tôi đã phải mở rộng TestCase trong mỗi Bài kiểm tra của mình. Đến lượt nó, nó đã phá vỡ các Thử nghiệm đơn vị làm việc trước đó đã sử dụng các chú thích JUnit4 để xác định các ngoại lệ dự kiến. Tìm kiếm của tôi để tìm cách tự động điền vào Test Suite đã đưa tôi đến chủ đề này, và cụ thể là câu trả lời của bạn, mà tôi tin là một trong số ít lý do mong muốn còn lại để tiếp tục với JUnit 3.
8bitjunkie

4

Bạn nên sử dụng JUnit 4. Tốt hơn.

Nhiều khung đã bắt đầu từ chối hỗ trợ JUnit 3.8.

Đây là từ tài liệu tham khảo Spring 3.0:

[Cảnh báo] Hệ thống phân cấp lớp Legacy JUnit 3.8 không được dùng nữa

Nói chung, bạn nên luôn cố gắng sử dụng bản phát hành ổn định mới nhất của khung khi bạn bắt đầu một cái gì đó mới.


1
  1. Cách tiếp cận "ưa thích" sẽ là sử dụng các chú thích đã được giới thiệu kể từ Junit 4. Chúng làm cho mọi thứ dễ dàng hơn (xem câu hỏi thứ hai của bạn)

  2. Bạn có thể sử dụng một khối thử / bắt đơn giản cho điều đó:


public void testForException() {
    try {
        Integer.parseInt("just a string");
        fail("Exception should have been thrown");
    } catch (final Exception e) {
        // expected
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.