Móc thực thi Before và After Suite trong jUnit 4.x


84

Tôi đang cố gắng thiết lập trước và chia nhỏ cho một tập hợp các bài kiểm tra tích hợp, sử dụng jUnit 4.4 để thực hiện các bài kiểm tra. Các giọt nước mắt cần được chạy một cách đáng tin cậy. Tôi đang gặp sự cố khác với TestNG, vì vậy tôi đang tìm cách chuyển trở lại jUnit. Những móc nào có sẵn để thực thi trước khi chạy bất kỳ thử nghiệm nào và sau khi tất cả các thử nghiệm đã hoàn thành?

Lưu ý: chúng tôi đang sử dụng maven 2 cho bản dựng của mình. Tôi đã thử sử dụng maven's pre-& post-integration-testphase, nhưng nếu kiểm tra không thành công, maven dừng lại và không chạy post-integration-test, điều này không có ích gì.


1
Đối với các thử nghiệm tích hợp, bạn nên sử dụng plugin maven-failsafe- thay vì chắc chắn. Điều này sẽ không bỏ qua post-integration-testnếu một bài kiểm tra không thành công. Xem thêm trang wiki này .
Chris H.

bạn có thể chia sẻ bạn thực hiện cuối cùng xin vui lòng?
vikramvi

Câu trả lời:


113

Có, có thể chạy các phương pháp thiết lập và loại bỏ trước và sau bất kỳ thử nghiệm nào trong bộ thử nghiệm một cách đáng tin cậy. Hãy để tôi chứng minh bằng mã:

package com.test;

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

@RunWith(Suite.class)
@SuiteClasses({Test1.class, Test2.class})
public class TestSuite {

    @BeforeClass
    public static void setUp() {
        System.out.println("setting up");
    }

    @AfterClass
    public static void tearDown() {
        System.out.println("tearing down");
    }

}

Vì vậy, Test1lớp của bạn sẽ trông giống như sau:

package com.test;

import org.junit.Test;


public class Test1 {
    @Test
    public void test1() {
        System.out.println("test1");
    }

}

... và bạn có thể tưởng tượng rằng nó Test2trông tương tự. Nếu bạn chạy TestSuite, bạn sẽ nhận được:

setting up
test1
test2
tearing down

Vì vậy, bạn có thể thấy rằng thiết lập / hủy bỏ chỉ chạy trước và sau tất cả các thử nghiệm, tương ứng.

Bí quyết: điều này chỉ hoạt động nếu bạn đang chạy bộ thử nghiệm và không chạy Test1 và Test2 dưới dạng các thử nghiệm JUnit riêng lẻ. Bạn đã đề cập rằng bạn đang sử dụng maven và plugin maven surefire thích chạy thử nghiệm riêng lẻ chứ không phải là một phần của bộ. Trong trường hợp này, tôi khuyên bạn nên tạo một lớp cha mà mỗi lớp thử nghiệm mở rộng. Sau đó, lớp cha chứa các phương thức @BeforeClass và @AfterClass được chú thích. Mặc dù không hoàn toàn sạch sẽ như phương pháp trên nhưng tôi nghĩ nó sẽ hiệu quả với bạn.

Đối với vấn đề với các thử nghiệm không thành công, bạn có thể đặt maven.test.error.ignore để bản dựng tiếp tục trên các thử nghiệm không thành công. Điều này không được khuyến khích như một thực hành liên tục, nhưng nó sẽ giúp bạn hoạt động cho đến khi tất cả các bài kiểm tra của bạn vượt qua. Để biết thêm chi tiết, hãy xem tài liệu về maven chắc chắn .


2
Điều này hoạt động hoàn hảo đối với tôi khi tôi truy cập vào plugin maven-surefire-và tạo một danh sách bao gồm trỏ đến bộ phần mềm mà tôi muốn chạy.
Jherico

2
Kể từ JUnit 4.8.2, điều này không hoạt động tốt với các bài kiểm tra tham số hóa. Phương thức @BeforeClass của Suite sẽ được chạy sau phương thức @ Parameterized.Parameters của bài kiểm tra, ngăn chặn mọi sự phụ thuộc vào thiết lập của Suite.
Anm

Theo bản thân tôi, khi sử dụng @Theories, lệnh gọi phương thức @DataPoints được gọi sau @BeforeClass của Suite.
Anm

18
Xin lỗi vì lỗi này - nhưng việc thêm BeforeClass / AfterClass vào một siêu lớp không hoạt động như mong đợi - chúng vẫn được gọi sau khi mỗi lớp thử nghiệm hoàn thành. Điều này dành cho hậu thế.
Subu Sankara Subramanian vào

3
Đây có còn là một cách tiếp cận hợp lệ không? Làm cách nào để bạn tránh phải liệt kê danh sách các lớp thử nghiệm trong chú thích SuiteClasses?
Burhan Ali

33

Một đồng nghiệp của tôi đã đề xuất như sau: bạn có thể sử dụng RunListener tùy chỉnh và triển khai phương thức testRunFinishing (): http://junit.sourceforge.net/javadoc/org/junit/runner/notification/RunListener.html#testRunFinishing(org. junit.runner.Result)

Để đăng ký RunListener, chỉ cần định cấu hình plugin surefire như sau: http://maven.apache.org/surefire/maven-surefire-plugin/examples/junit.html phần "Sử dụng trình nghe và báo cáo tùy chỉnh"

Cấu hình này cũng nên được chọn bởi plugin an toàn dự phòng. Giải pháp này rất tuyệt vì bạn không phải chỉ định Suite, các lớp kiểm tra tra cứu hoặc bất kỳ thứ nào trong số này - nó cho phép Maven thực hiện điều kỳ diệu của nó, đợi tất cả các bài kiểm tra kết thúc.


5
+1 Đó là giải pháp hữu dụng đầu tiên mà tôi đã thấy mà không cần bảo trì rườm rà của một lớp Suites!
Stefan Haberl


7

Sử dụng chú thích, bạn có thể làm như sau:

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

class SomethingUnitTest {
    @BeforeClass
    public static void runBeforeClass()
    {

    }

    @AfterClass
    public static void runAfterClass()
    {  

    }

    @Before  
    public void setUp()
    {

    }

    @After
    public void tearDown()
    {

    }

    @Test
    public void testSomethingOrOther()
    {

    }

}

4
Việc thiết lập & xé nhỏ cần được thực hiện một lần mỗi lần chạy. Điều này sẽ chỉ hữu ích nếu tất cả các bài kiểm tra đều ở trong một lớp.
sblundy 17/09/08

3

Đây, chúng tôi

  • đã nâng cấp lên JUnit 4.5,
  • đã viết chú thích để gắn thẻ từng lớp hoặc phương thức thử nghiệm cần một dịch vụ hoạt động,
  • đã viết các trình xử lý cho mỗi chú thích chứa các phương thức tĩnh để triển khai thiết lập và chia nhỏ dịch vụ,
  • đã mở rộng Trình chạy thông thường để xác định vị trí các chú thích trong các thử nghiệm, thêm các phương thức xử lý tĩnh vào chuỗi thực thi thử nghiệm tại các điểm thích hợp.

2

Đối với "Lưu ý: chúng tôi đang sử dụng maven 2 cho bản dựng của mình. Tôi đã thử sử dụng giai đoạn kiểm tra trước và sau tích hợp của maven, nhưng nếu kiểm tra không thành công, maven dừng và không chạy kiểm tra sau tích hợp , không ích gì. "

bạn có thể dùng thử dự phòng-plugin thay thế, tôi nghĩ rằng nó có cơ sở để đảm bảo việc dọn dẹp xảy ra bất kể trạng thái thiết lập hay giai đoạn trung gian


Có, plugin an toàn dự phòng sẽ cho phép bạn chỉ định thiết lập và gỡ bỏ cụ thể. Mặc dù tôi không nghĩ rằng an toàn dự phòng tồn tại vào thời điểm câu hỏi này được đăng.
Jason Axelson

2

Với điều kiện là tất cả các bài kiểm tra của bạn có thể mở rộng một lớp "kỹ thuật" và nằm trong cùng một gói, bạn có thể thực hiện một mẹo nhỏ:

public class AbstractTest {
  private static int nbTests = listClassesIn(<package>).size();
  private static int curTest = 0;

  @BeforeClass
  public static void incCurTest() { curTest++; }

  @AfterClass
  public static void closeTestSuite() {
      if (curTest == nbTests) { /*cleaning*/ }             
  }
}

public class Test1 extends AbstractTest {
   @Test
   public void check() {}
}
public class Test2 extends AbstractTest {
   @Test
   public void check() {}
}

Cần biết rằng giải pháp này có rất nhiều nhược điểm:

  • phải thực hiện tất cả các thử nghiệm của gói
  • phải phân lớp con một lớp "techincal"
  • bạn không thể sử dụng @BeforeClass và @AfterClass bên trong các lớp con
  • nếu bạn chỉ thực hiện một thử nghiệm trong gói, việc dọn dẹp sẽ không được thực hiện
  • ...

Để biết thông tin: listClassesIn () => Làm thế nào để bạn tìm thấy tất cả các lớp con của một lớp nhất định trong Java?


1
điều này không đúng theo như các thử nghiệm của riêng tôi cho thấy. Tôi có một lớp siêu bắt đầu một con cá thủy tinh nhúng trên lớp trước và tắt nó sau lớp sau. Sau đó tôi có 2 lớp học mở rộng từ lớp siêu cấp đó. Lớp before được thực thi trước khi chạy các bài kiểm tra được xác định trong mỗi lớp.
Jonathan Morales Vélez

0

Theo như tôi biết thì không có cơ chế nào để thực hiện việc này trong JUnit, tuy nhiên bạn có thể thử phân lớp con Suite và ghi đè phương thức run () bằng một phiên bản có cung cấp hook.


0

Vì maven-surefire-plugin không chạy lớp Suite trước mà xử lý các lớp thử nghiệm và bộ phần mềm giống nhau, vì vậy chúng ta có thể định cấu hình plugin như bên dưới để chỉ bật các lớp bộ ứng dụng và tắt tất cả các thử nghiệm. Suite sẽ chạy tất cả các bài kiểm tra.

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.5</version>
            <configuration>
                <includes>
                    <include>**/*Suite.java</include>
                </includes>
                <excludes>
                    <exclude>**/*Test.java</exclude>
                    <exclude>**/*Tests.java</exclude>
                </excludes>
            </configuration>
        </plugin>

0

Cách duy nhất tôi nghĩ lúc đó để có được chức năng bạn muốn là làm một số việc như

import junit.framework.Test;  
import junit.framework.TestResult;  
import junit.framework.TestSuite;  

public class AllTests {  
    public static Test suite() {  
        TestSuite suite = new TestSuite("TestEverything");  
        //$JUnit-BEGIN$  
        suite.addTestSuite(TestOne.class);  
        suite.addTestSuite(TestTwo.class);  
        suite.addTestSuite(TestThree.class);  
        //$JUnit-END$  
     }  

     public static void main(String[] args)  
     {  
        AllTests test = new AllTests();  
        Test testCase = test.suite();  
        TestResult result = new TestResult();  
        setUp();  
        testCase.run(result);  
        tearDown();  
     }  
     public void setUp() {}  
     public void tearDown() {}  
} 

Tôi sử dụng một cái gì đó như thế này trong nhật thực, vì vậy tôi không chắc nó di động như thế nào bên ngoài môi trường đó


3
Đây là một ví dụ cho JUnit3 và OP đã yêu cầu JUnit4, nhưng đề phòng một số người dùng JUnit3 tìm thấy câu hỏi này ... Đối với JUnit3, tốt hơn là nên loại bỏ phương thức main () và có phương thức suite () bọc TestSuite trong một lớp con của junit.extensions.TestSetup. Bạn vẫn có những cảnh báo tương tự như ví dụ của Julie về việc chạy các lớp thử nghiệm riêng lẻ trong IDE của bạn.
NamshubWriter

0

Nếu bạn không muốn tạo một bộ và phải liệt kê tất cả các lớp thử nghiệm của mình, bạn có thể sử dụng phản chiếu để tìm số lượng lớp thử nghiệm động và đếm ngược trong một lớp cơ sở @AfterClass để thực hiện xé ảnh chỉ một lần:

public class BaseTestClass
{
    private static int testClassToRun = 0;

    // Counting the classes to run so that we can do the tear down only once
    static {
        try {
            Field field = ClassLoader.class.getDeclaredField("classes");
            field.setAccessible(true);

            @SuppressWarnings({ "unchecked", "rawtypes" })
            Vector<Class> classes = (Vector<Class>) field.get(BlockJUnit4ClassRunner.class.getClassLoader());
            for (Class<?> clazz : classes) {
                if (clazz.getName().endsWith("Test")) {
                    testClassToRun++;
                }
            }
        } catch (Exception ignore) {
        }
    }

    // Setup that needs to be done only once
    static {
        // one time set up
    }

    @AfterClass
    public static void baseTearDown() throws Exception
    {
        if (--testClassToRun == 0) {
            // one time clean up
        }
    }
}

Nếu bạn thích sử dụng @BeforeClass thay vì các khối tĩnh, bạn cũng có thể sử dụng cờ boolean để thực hiện đếm phản xạ và kiểm tra thiết lập chỉ một lần ở lần gọi đầu tiên. Hy vọng điều này sẽ giúp ai đó, tôi đã mất một buổi chiều để tìm ra một cách tốt hơn là liệt kê tất cả các lớp trong một bộ.

Bây giờ tất cả những gì bạn cần làm là mở rộng lớp này cho tất cả các lớp thử nghiệm của bạn. Chúng tôi đã có một lớp cơ sở để cung cấp một số nội dung chung cho tất cả các bài kiểm tra của chúng tôi vì vậy đây là giải pháp tốt nhất cho chúng tôi.

Cảm hứng đến từ câu trả lời SO này https://stackoverflow.com/a/37488620/5930242

Nếu bạn không muốn mở rộng lớp học này ở khắp mọi nơi, câu trả lời SO cuối cùng này có thể làm những gì bạn muốn.

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.