คำสั่ง RunWith หลายรายการใน jUnit


113

ฉันเขียนการทดสอบหน่วยและต้องการใช้JUnitParamsRunnerและMockitoJUnitRunnerสำหรับชั้นเรียนการทดสอบเดียว

ขออภัยสิ่งต่อไปนี้ใช้ไม่ได้:

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

มีวิธีใช้ทั้ง Mockito และ JUnitParams ในคลาสทดสอบเดียวหรือไม่?



2
มีตัวอย่างที่ดีของที่นี่ยัง: blog.project13.pl/index.php/coding/1077/...
falsarella

คำตอบ:


110

คุณไม่สามารถทำได้เนื่องจากตามข้อมูลจำเพาะคุณไม่สามารถใส่คำอธิบายประกอบเดียวกันซ้ำสองครั้งในองค์ประกอบคำอธิบายประกอบเดียวกันได้

แล้วทางออกคืออะไร? วิธีแก้ปัญหาคือใส่เพียงหนึ่งเดียว@RunWith()กับนักวิ่งที่คุณไม่สามารถยืนได้โดยปราศจากและแทนที่คนอื่นด้วยสิ่งอื่น ในกรณีของคุณฉันเดาว่าคุณจะลบออกMockitoJUnitRunnerและดำเนินการตามโปรแกรม

ในความเป็นจริงสิ่งเดียวที่มันทำงาน:

MockitoAnnotations.initMocks(test);

ในจุดเริ่มต้นของกรณีทดสอบ ดังนั้นทางออกที่ง่ายที่สุดคือใส่รหัสนี้ลงในsetUp()method:

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

ผมไม่แน่ใจ แต่อาจจะเป็นคุณควรหลีกเลี่ยงหลายสายของวิธีการนี้ใช้ธง:

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

อย่างไรก็ตามวิธีที่ดีกว่าอาจใช้วิธีแก้ปัญหาที่ใช้ซ้ำได้กับกฎของ JUnt

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

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

ตอนนี้เพียงเพิ่มบรรทัดต่อไปนี้ในชั้นเรียนทดสอบของคุณ:

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

และคุณสามารถเรียกใช้กรณีทดสอบนี้กับนักวิ่งคนใดก็ได้ที่คุณต้องการ


13
การตรวจสอบmockInitializedไม่ถูกต้อง คุณต้องการมีการเยาะเย้ยใหม่สำหรับทุก tetst
BetaRide

1
@BetaRide มันขึ้นอยู่กับความต้องการของคุณ บางครั้งคุณต้องการเริ่มต้นการจำลองทุกครั้งบางครั้งก็ไม่
AlexR

หากคุณต้องการตั้งค่าหนึ่งครั้งต่อไฟล์คลาสคุณสามารถใช้ BeforeClass แทน Before ซึ่งจะเรียกใช้ครั้งเดียวและครั้งเดียวต่อไฟล์ทดสอบ
InfernalRapture

56

ตั้งแต่ JUnit 4.7 และ Mockito 1.10.17 ฟังก์ชันนี้มีอยู่ในตัว มีorg.mockito.junit.MockitoRuleชั้นเรียน คุณสามารถนำเข้าและเพิ่มบรรทัดได้

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

ไปยังชั้นเรียนทดสอบของคุณ


2
สำหรับ Mockito รุ่นเก่า (ดูเหมือนจะเป็น 1.10.5) คุณต้องใช้:@Rule public MockitoJUnitRule mockito = new MockitoJUnitRule(this);
Cliff Sun

MockitoAnnotations.initMocks(this)สร้างล้อเลียนได้ช้ามาก วิธีที่มีประสิทธิภาพที่สุดคือการใช้ @Runwith (MockitoJunitRunner.class)
ant2009

16

โซลูชันนี้ใช้ได้กับนักวิ่งที่เป็นไปได้ทุกคนไม่ใช่แค่ตัวอย่างม็อกโต ตัวอย่างเช่น; สำหรับฤดูใบไม้ผลิเพียงแค่เปลี่ยนคลาสของนักวิ่งและเพิ่มคำอธิบายประกอบที่จำเป็น

@RunWith(JUnitParamsRunner.class)
public class DatabaseModelTest {

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

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

DatabaseModelTestจะดำเนินการโดย JUnit TestMockitoJUnitRunnerขึ้นอยู่กับมัน (โดยตรรกะ) และมันจะทำงานภายในของหลักในวิธีการในระหว่างการโทร@Test JUnitCore.runClasses(TestMockitoJUnitRunner.class)วิธีนี้ช่วยให้มั่นใจได้ว่านักวิ่งหลักจะเริ่มต้นอย่างถูกต้องก่อนที่static class TestMockitoJUnitRunnerนักวิ่งย่อยจะวิ่งโดยใช้@RunWithคำอธิบายประกอบที่ซ้อนกันหลายรายการพร้อมคลาสทดสอบที่ขึ้นอยู่กับ

นอกจากนี้ในhttps://bekce.github.io/junit-multiple-runwith-dependent-tests


3
การโทรJUnitCore.runClasses()โดยไม่ตรวจสอบผลลัพธ์จะทำให้คุณเสี่ยงต่อการปิดบังข้อผิดพลาดจากการทดสอบภายใน assert(JUnitCore.runClasses(TestMockitoJUnitRunner.class).wasSuccessful());อย่างน้อยจะรายงานข้อผิดพลาดให้คุณทราบ
Robotnik


2

ในกรณีของฉันฉันพยายามเลียนแบบวิธีการบางอย่างในถั่วสปริงและ

MockitoAnnotations.initMocks(test);

ไม่ทำงาน แต่คุณต้องกำหนด bean นั้นเพื่อสร้างโดยใช้วิธีการจำลองภายในไฟล์ xml ของคุณดังต่อไปนี้

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

และเพิ่มถั่วนั้นโดยอัตโนมัติในชั้นเรียนทดสอบของคุณดังต่อไปนี้

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

0

ตรวจสอบลิงค์นี้https://bekce.github.io/junit-multiple-runwith-dependent-tests/ โดยใช้วิธีนี้ฉันรวม @RunWith (Parameterized.class) - ตัววิ่งด้านนอก - กับ @RunWith (MockitoJUnitRunner.class) - นักวิ่งด้านใน การปรับแต่งเพียงอย่างเดียวที่ฉันต้องเพิ่มคือการทำให้ตัวแปรสมาชิกของฉันอยู่ในคลาสนอก / ตัววิ่งแบบคงที่เพื่อให้สามารถเข้าถึงได้สำหรับนักวิ่ง / ชั้นใน / ชั้นซ้อน เสี่ยงโชคและสนุก


0

ฉันต้องการเรียกใช้SWTBotJunit4ClassRunnerและorg.junit.runners พารามิเตอร์ในเวลาเดียวกันฉันมีการทดสอบพาราเมตริกและฉันต้องการจับภาพหน้าจอเมื่อการทดสอบ SWT ล้มเหลว (คุณลักษณะภาพหน้าจอมีให้โดย SWTBotJunit4ClassRunner ) คำตอบของ @ bekce นั้นยอดเยี่ยมและเป็นอันดับแรกที่ต้องการไปในเส้นทางนั้น แต่มันก็แปลก ๆ ที่ผ่านข้อโต้แย้ง หรือทำ parametrized ในคลาสย่อยและสูญเสียข้อมูลว่าการทดสอบที่แน่นอนผ่าน / ล้มเหลวและมีเพียงภาพหน้าจอสุดท้าย (เนื่องจากชื่อภาพหน้าจอได้รับชื่อจากการทดสอบเอง) ดังนั้นไม่ว่าจะด้วยวิธีใดมันก็ค่อนข้างยุ่ง

ในกรณีของฉันSWTBotJunit4ClassRunnerนั้นง่ายพอดังนั้นฉันจึงโคลนซอร์สโค้ดของคลาสตั้งชื่อให้เป็นParametrizedSc screenshotRunnerของฉันเองและเมื่อต้นฉบับขยายTestRunnerชั้นเรียนของฉันกำลังขยาย Parameterizedคลาสดังนั้นโดยแล้วฉันสามารถใช้ตัววิ่งของตัวเองได้ แทนที่จะเป็นสองรายการก่อนหน้า การต้มนักวิ่งของตัวเองขยายไปด้านบนของนักวิ่งพารามิเตอร์ในขณะที่ใช้คุณลักษณะภาพหน้าจอด้านบนตอนนี้การทดสอบของฉันใช้นักวิ่ง "ไฮบริด" นี้และการทดสอบทั้งหมดทำงานได้ตามที่คาดไว้ทันที (ไม่จำเป็นต้องเปลี่ยนแปลงอะไรในการทดสอบ)

นี่คือลักษณะที่ปรากฏ (เพื่อความกระชับฉันลบความคิดเห็นทั้งหมดออกจากรายการ):

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

คุณยังสามารถลองสิ่งนี้:

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

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

2
วิธีนี้ใช้ไม่ได้ผลเฉพาะคำอธิบายประกอบระดับย่อยเท่านั้นที่จะดำเนินการ
PaulNUK

ไม่ได้ผล - เฉพาะคำอธิบายประกอบ MockitoJUnitRunner เท่านั้นที่จะถูกนำมาพิจารณา
Przemek Bielicki
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.