Nhiều câu lệnh RunWith trong jUnit


113

Tôi viết bài kiểm tra đơn vị và muốn sử dụng JUnitParamsRunnerMockitoJUnitRunnercho một lớp kiểm tra.

Rất tiếc, những điều sau không hoạt động:

@RunWith(MockitoJUnitRunner.class)
@RunWith(JUnitParamsRunner.class)
public class DatabaseModelTest {
  // some tests
}

Có cách nào để sử dụng cả Mockito và JUnitParams trong một lớp thử nghiệm không?



2
Có một ví dụ hay ở đây nữa: blog.project13.pl/index.php/coding/1077/…
falsarella,

Câu trả lời:


110

Bạn không thể làm điều này vì theo thông số kỹ thuật, bạn không thể đặt cùng một chú thích hai lần trên cùng một phần tử được chú thích.

Vậy giải pháp là gì? Giải pháp là chỉ đặt một @RunWith()với người chạy mà bạn không thể thiếu và thay thế một cái khác bằng thứ khác. Trong trường hợp của bạn, tôi đoán bạn sẽ xóa MockitoJUnitRunnervà làm theo chương trình những gì nó làm.

Trong thực tế, điều duy nhất nó chạy:

MockitoAnnotations.initMocks(test);

trong phần đầu của test case. Vì vậy, giải pháp đơn giản nhất là đặt mã này vào setUp()phương thức:

@Before
public void setUp() {
    MockitoAnnotations.initMocks(this);
}

Tôi không chắc, nhưng có lẽ bạn nên tránh nhiều lần gọi phương thức này bằng cách sử dụng cờ:

private boolean mockInitialized = false;
@Before
public void setUp() {
    if (!mockInitialized) {
        MockitoAnnotations.initMocks(this);
        mockInitialized = true;  
    }
}

Tuy nhiên tốt hơn, giải pháp có thể tái sử dụng có thể được thực hiện với các quy tắc của JUnt.

public class MockitoRule extends TestWatcher {
    private boolean mockInitialized = false;

    @Override
    protected void starting(Description d) {
        if (!mockInitialized) {
            MockitoAnnotations.initMocks(this);
            mockInitialized = true;  
        }
    }
}

Bây giờ chỉ cần thêm dòng sau vào lớp thử nghiệm của bạn:

@Rule public MockitoRule mockitoRule = MockitoJUnit.rule();

và bạn có thể chạy trường hợp thử nghiệm này với bất kỳ người chạy nào bạn muốn.


12
Kiểm tra cho mockInitializedlà sai. Bạn muốn có một mô hình mới cho mỗi dịp Tết.
BetaRide

1
@BetaRide, nó tùy thuộc vào nhu cầu của bạn. Đôi khi bạn muốn khởi tạo mô hình mọi lúc, đôi khi không.
AlexR

Nếu bạn muốn thiết lập một lần cho mỗi tệp lớp, bạn có thể sử dụng BeforeClass thay vì Before, sẽ được gọi một lần và chỉ một lần cho mỗi tệp thử nghiệm.
InfernalRapture,

56

Kể từ JUnit 4.7 và Mockito 1.10.17, chức năng này được tích hợp sẵn; có một org.mockito.junit.MockitoRulelớp học. Bạn chỉ cần nhập nó và thêm dòng

@Rule public MockitoRule mockitoRule = MockitoJUnit.rule();

đến lớp thử nghiệm của bạn.


2
Đối với các phiên bản cũ hơn của Mockito (có vẻ như giảm xuống 1.10.5), bạn phải sử dụng:@Rule public MockitoJUnitRule mockito = new MockitoJUnitRule(this);
Cliff Sun

MockitoAnnotations.initMocks(this)rất chậm để tạo ra các chế độ giả. Cách hiệu quả nhất là sử dụng @Runwith (MockitoJunitRunner.class)
ant2009

16

Giải pháp này hoạt động cho mọi người chạy có thể, không chỉ ví dụ mockito này. Ví dụ; đối với Spring, chỉ cần thay đổi các lớp chạy và thêm các chú thích cần thiết.

@RunWith(JUnitParamsRunner.class)
public class DatabaseModelTest {

    @Test
    public void subRunner() throws Exception {
        JUnitCore.runClasses(TestMockitoJUnitRunner.class);
    }

    @RunWith(MockitoJUnitRunner.class)
    public static class TestMockitoJUnitRunner {
    }
}

DatabaseModelTestsẽ được điều hành bởi JUnit. TestMockitoJUnitRunnerphụ thuộc vào nó (theo logic) và nó sẽ được chạy bên trong main trong một @Testphương thức, trong khi gọi JUnitCore.runClasses(TestMockitoJUnitRunner.class). Phương pháp này đảm bảo trình chạy chính được khởi động chính xác trước khi trình static class TestMockitoJUnitRunnerchạy phụ chạy, triển khai hiệu quả nhiều @RunWithchú thích lồng nhau với các lớp kiểm tra phụ thuộc.

Cũng trên https://bekce.github.io/junit-multiple-runwith-dependent-tests


3
Bằng cách gọi điện JUnitCore.runClasses()mà không kiểm tra kết quả, bạn có nguy cơ che dấu các lỗi từ bài kiểm tra bên trong. assert(JUnitCore.runClasses(TestMockitoJUnitRunner.class).wasSuccessful());ít nhất sẽ thông báo lỗi cho bạn
Robotnik


2

Trong trường hợp của tôi, tôi đang cố gắng Mô phỏng một số phương pháp trong Spring bean và

MockitoAnnotations.initMocks(test);

không hoạt động. Thay vào đó, bạn phải xác định bean đó được xây dựng bằng cách sử dụng phương thức giả bên trong tệp xml của bạn như sau.

...
<bean id="classWantedToBeMocked" class="org.mockito.Mockito" factory-method="mock">
    <constructor-arg value="com.fullpath.ClassWantedToBeMocked" />
</bean>
...

và thêm bean đó bằng autowedly bên trong lớp thử nghiệm của bạn như sau.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="file:springconfig.xml")
public class TestClass {
    ...
    @Autowired
    private ClassWantedToBeMocked classWantedToBeMocked;
    ...
    when(classWantedToBeMocked.methodWantedToBeMocked()).thenReturn(...);
    ...
}

0

hãy xem liên kết này https://bekce.github.io/junit-multiple-runwith-dependent-tests/ bằng cách sử dụng cách tiếp cận này, tôi đã kết hợp @RunWith (Parameterized.class) - bên ngoài - với @RunWith (MockitoJUnitRunner.class) - người chạy trong. Tinh chỉnh duy nhất tôi phải thêm là làm cho các biến thành viên của tôi trong lớp bên ngoài / người chạy tĩnh để làm cho chúng có thể truy cập được cho người chạy / lớp bên trong / lồng nhau. gook may mắn và tận hưởng.


0

Tôi muốn chạy SWTBotJunit4ClassRunnerorg.junit.runners.Parameterized đồng thời, tôi có các bài kiểm tra tham số và tôi muốn chụp ảnh màn hình khi kiểm tra SWT không thành công (tính năng ảnh chụp màn hình được cung cấp bởi SWTBotJunit4ClassRunner ). Câu trả lời của @ bekce rất tuyệt và lần đầu tiên muốn đi theo con đường đó nhưng nó hoặc là kỳ quặc khi đi qua các lập luận. Hoặc thực hiện tham số hóa trong lớp con và mất thông tin những bài kiểm tra chính xác đã vượt qua / không thành công và chỉ có ảnh chụp màn hình cuối cùng (vì tên ảnh chụp màn hình lấy tên từ chính bài kiểm tra). Vì vậy, dù theo cách nào thì nó cũng hơi lộn xộn.

Trong trường hợp của tôi, SWTBotJunit4ClassRunner đủ đơn giản, vì vậy tôi đã sao chép mã nguồn của lớp, đặt tên riêng cho nó là ParametrizedScreenshotRunner và nơi nguyên bản đang mở rộng TestRunner , lớp của tôi đang mở rộng Tham số lớp nên về bản chất, tôi có thể sử dụng trình chạy của riêng mình thay vì hai phần trước. Phần chạy đua của riêng tôi mở rộng trên đầu của người chạy Parameterized trong khi triển khai tính năng chụp ảnh màn hình trên đầu nó, bây giờ bài kiểm tra của tôi sử dụng người chạy "lai" này và tất cả các bài kiểm tra hoạt động như mong đợi ngay lập tức (không cần thay đổi bất kỳ điều gì bên trong các bài kiểm tra).

Đây là cách nó trông như thế này (để ngắn gọn, tôi đã xóa tất cả các nhận xét khỏi danh sách):

package mySwtTests;

import org.junit.runners.Parameterized;
import org.eclipse.swtbot.swt.finder.junit.ScreenshotCaptureListener;
import org.junit.runner.notification.RunListener;
import org.junit.runner.notification.RunNotifier;

public class ParametrizedScreenshotRunner extends TestRu Parameterized {

    public ParametrizedScreenshotRunner(Class<?> klass) throws Throwable {
        super(klass);
    }

    public void run(RunNotifier notifier) {
        RunListener failureSpy = new ScreenshotCaptureListener();
        notifier.removeListener(failureSpy); // remove existing listeners that could be added by suite or class runners
        notifier.addListener(failureSpy);
        try {
            super.run(notifier);
        } finally {
            notifier.removeListener(failureSpy);
        }
    }
}

-15

Bạn cũng có thể thử điều này:

@RunWith(JUnitParamsRunner.class)
public class AbstractTestClass {
  // some tests
}

@RunWith(MockitoJUnitRunner.class)
public class DatabaseModelTest extends AbstractTestClass {
  // some tests
}

2
Điều này sẽ không hoạt động, chỉ chú thích lớp phụ mới được xử lý.
PaulNUK

không hoạt động - chỉ có chú thích MockitoJUnitRunner mới được tính đến
Przemek Bielicki
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.