2013-09-02 62 views
15

Tôi có một lớp, mà tôi sử dụng làm cơ sở cho các bài kiểm tra đơn vị của mình. Trong lớp này, tôi khởi tạo toàn bộ môi trường cho các bài kiểm tra của tôi, thiết lập ánh xạ cơ sở dữ liệu, nhập một số bản ghi cơ sở dữ liệu trên nhiều bảng, vv Lớp đó có phương thức với chú thích @BeforeClass thực hiện khởi tạo. Tiếp theo, tôi mở rộng lớp đó với các lớp cụ thể mà tôi có các phương thức @Test.THÁNG SÁU: chỉ chạy thiết lập một lần cho một số lượng lớn các lớp kiểm tra

Câu hỏi của tôi là vì lớp trước hoàn toàn giống nhau đối với tất cả các lớp kiểm tra này, làm cách nào để đảm bảo rằng chúng chỉ chạy một lần cho tất cả các bài kiểm tra. Một giải pháp đơn giản là tôi có thể giữ tất cả các bài kiểm tra trong một lớp. Tuy nhiên, số lượng các bài kiểm tra là rất lớn, chúng cũng được phân loại dựa trên các đầu chức năng. Vì vậy, chúng được đặt trong các lớp khác nhau. Tuy nhiên, vì chúng cần thiết lập chính xác, chúng kế thừa @BeforeClass. Kết quả là toàn bộ thiết lập được thực hiện ít nhất một lần cho mỗi lớp thử nghiệm, chiếm nhiều thời gian hơn tổng số mà tôi muốn.

Mặc dù vậy, tôi có thể đặt tất cả các gói con dưới một gói, vì vậy nếu có cách, tôi có thể chạy thiết lập một lần cho tất cả các thử nghiệm trong gói đó, nó sẽ rất tuyệt.

+0

Bạn đã xem xét một cái gì đó như thế này: http://stackoverflow.com/questions/6580670/testsuite-setup-in-junit-4 – efan

+0

Giới hạn đã biết. Bởi vì các vấn đề như vậy cá nhân tôi thích [testng] (http://testng.org/doc/documentation-main.html) khuôn khổ. –

+0

@ G.Demecki bạn đề cập đến khuôn khổ testNG - tại sao bạn không tạo ra một câu trả lời với cách TestNG để làm điều này cho bất cứ ai có thể tự hỏi? Câu hỏi tràn ngăn xếp tương tự cho TestNG này dường như không tồn tại. –

Trả lời

5

JUnit không hỗ trợ này, bạn sẽ phải sử dụng Java tiêu chuẩn công việc ở quanh cho độc thân: Di chuyển các mã cài đặt chung vào một khối mã tĩnh và sau đó gọi một phương pháp có sản phẩm nào trong lớp này:

static { 
    ...init code here... 
} 

public static void init() {} // Empty method to trigger the execution of the block above 

Hãy chắc chắn rằng tất cả các thử nghiệm gọi init(), ví dụ như tôi đặt nó vào phương thức @BeforeClass. Hoặc đặt khối mã tĩnh vào một lớp cơ sở được chia sẻ.

Ngoài ra, sử dụng một biến toàn cầu:

private static boolean initialize = true; 
public static void init() { 
    if(!initialize) return; 
    initialize = false; 

    ...init code here... 
} 
+1

Biến phải tĩnh, nếu không nó sẽ không hoạt động hoặc biên dịch ;-) Khai báo chính phương thức tĩnh là không cần thiết. Đặc biệt khi (giống như trong các bài kiểm tra tôi vừa mới bắt gặp), bạn cần những thứ như @Inject hoặc các cơ chế DI khác, giữ một phương thức init() không tĩnh gọi các biến helper tĩnh hoạt động tốt nhất. –

+0

@WernerKeil Cảm ơn, đã khắc phục. –

0

Không chắc chắn nếu có ai vẫn đang sử dụng JUnit và cố gắng khắc phục sự cố mà không sử dụng Spring Runner (không có tích hợp mùa xuân). TestNG có tính năng này. Nhưng đây là giải pháp dựa trên JUnit.

Tạo RunOnce cho mỗi thao tác chuỗi như vậy. Điều này duy trì một danh sách các lớp mà hoạt động đã chạy.

public class RunOnceOperation { 
private static final ThreadLocal t = new ThreadLocal(); 

public void run(Function f) { 
    if (t.get() == null) { 
     t.set(Arrays.asList(getClass())); 
     f.apply(0); 
    } else { 
     if (!((List) t.get()).contains(getClass())) { 
      ((List) t.get()).add(getClass()); 
      f.apply(0); 
     } 
    } 
    } 
} 

Quay trở lại bài kiểm tra đơn vị của bạn

@Before 
public beforeTest() { 
    operation.run(new Function<Integer, Void>() { 
     @Override 
     public Void apply(Integer t) { 
      checkBeanProperties(); 
      return null; 
     } 
    }); 
} 

private void checkBeanProperties() { 
    //I only want to check this once per class. 
    //Also my bean check needs instance of the class and can't be static. 
} 


My function interface is like this: 

interface Function<I,O> { 
O apply(I i); 
} 

Khi bạn sử dụng cách này, bạn có thể thực hiện các hoạt động một lần mỗi lớp sử dụng ThreadLocal.

+0

Đoán bạn có thể tái sử dụng một số java.util.function trong Java 8 cho điều đó. –

1

Tạo một lớp cơ sở cho tất cả các xét nghiệm:

public class BaseTest { 
    static{ 
     /*** init code here ***/ 
    } 
} 

và mỗi bài kiểm tra nên kế thừa từ nó:

public class SomeTest extends BaseTest { 

} 
12

Với bộ kiểm tra Junit4 bạn có thể làm một cái gì đó như thế này:

@RunWith(Suite.class) 
@Suite.SuiteClasses({ Test1IT.class, Test2IT.class }) 
public class IntegrationTestSuite 
{ 
    @BeforeClass 
    public static void setUp() 
    { 
     System.out.println("Runs before all tests in the annotation above."); 
    } 

    @AfterClass 
    public static void tearDown() 
    { 
     System.out.println("Runs after all tests in the annotation above."); 
    } 
} 

Sau đó, bạn chạy lớp này vì bạn sẽ chạy một lớp kiểm tra bình thường và nó sẽ chạy tất cả các bài kiểm tra của bạn.

0

Bạn có thể tạo một lớp BaseTest với phương thức @BeforeClass, sau đó có tất cả các thử nghiệm khác được kế thừa từ đó. Bằng cách này, khi mỗi đối tượng thử nghiệm được xây dựng, @BeforeClass được thực thi.

Cũng tránh thực hiện nó chỉ một lần cho tất cả các bộ thử nghiệm, vì tất cả các trường hợp thử nghiệm phải độc lập. @BeforeClass chỉ được thực hiện một lần cho mỗi trường hợp thử nghiệm, không phải là bộ thử nghiệm.