ฉันได้ดูคำถามต่อไปนี้แล้ว และมันไม่เหมือนกับคำถามของฉัน:
jMockit: จะคาดหวังการเรียก Constructor ไปยังวัตถุ Mocked ได้อย่างไร
คำถามนี้คล้ายกัน แต่คำตอบไม่เป็นประโยชน์สำหรับฉัน:
วิธีจำลอง Constructor เริ่มต้นของ คลาสเดทกับ JMockit?
สิ่งที่ฉันพยายามทำคือจำลองการเรียกคอนสตรัคเตอร์ไปที่ java.util.zip.ZipFile
โดยเฉพาะอันที่มีอาร์กิวเมนต์ java.io.File
ฉันต้องการให้ Constructor ส่งคืนอินสแตนซ์ของ ZipFile
อื่น ซึ่งฉันจะยกตัวอย่างด้วย Constructor ที่รับเฉพาะอาร์กิวเมนต์ String
เท่านั้น
การเรียกคอนสตรัคเตอร์นี้เกิดขึ้นภายในวิธีการภายใต้การทดสอบ ดังนั้นฉันจึงไม่สามารถฉีด ZipFile
ที่ฉันต้องการเป็นพารามิเตอร์ได้
ตัวอย่างเช่น โค้ดจะมีลักษณะดังนี้:
public void whatever() {
//some code
//some more code
foo();
//yet more unrelated code
}
private Blah foo() {
ZipFile zf;
//a bunch of code we don't care about
zf = new ZipFile(someFile);// I want to give it a known zipfile! mock this!
// some more code we don't care about
Enumeration<?> entries = zf.entries();
ZipEntry entry = (ZipEntry) entries.nextElement();
InputStream is = zf.getInputStream(entry)
//maybe some other calls to the ZipFile
// do something else
}
ความคิดแรกของฉันคือทำสิ่งต่อไปนี้ด้วยการเยาะเย้ยบางส่วนแบบคงที่:
final ZipFile test = new ZipFile("path/to/actual.zip");
new NonStrictExpectations() {
@Mocked("(java.io.File)")
ZipFile zf;
{
new ZipFile((File) any); result = test;
}
};
แต่สิ่งนี้จะไม่ทำงานตามที่ระบุในบรรทัดนี้ในบทช่วยสอน: constructors have void return type, so it makes no sense to record return values for them
ความคิดที่สองของฉันคือลองทำสิ่งต่อไปนี้:
new NonStrictExpectations() {
{
newInstance("java.util.zip.ZipFile", new File("path/to/actual.zip"));
}
};
แต่สิ่งนี้จะส่งสิ่งต่อไปนี้เมื่อพยายามเตรียมใช้งานไฟล์:
java.util.zip.ZipException: error in opening zip file
at java.util.zip.ZipFile.open(Native Method)
at java.util.zip.ZipFile.<init>(Unknown Source)
at java.util.zip.ZipFile.<init>(Unknown Source)
ความคิดที่สามของฉันคือการใช้ @MockClass
ดังต่อไปนี้:
@Before
public void setUp() throws Exception {
Mockit.setUpMocks(MockedZipFile.class);
}
@After
public void tearDown() {
Mockit.tearDownMocks();
}
@MockClass(realClass=ZipFile.class)
public static class MockedZipFile {
public ZipFile it;
@Mock
public void $init(File f) throws ZipException, IOException {
it = new ZipFile("path/to/actual.zip");//this is what would be called
}
}
แต่นี่เป็นการเยาะเย้ยอื่น ๆ ที่ฉันมีซึ่งโหลดไฟล์การกำหนดค่าสำหรับส่วนอื่นของคลาสทดสอบของฉัน ไม่ต้องพูดถึงฉันต้องการไฟล์ zip ที่แตกต่างกันสำหรับกรณีทดสอบที่แตกต่างกัน
ฉันคิดว่าฉันสามารถเยาะเย้ยทุกสิ่งที่ ZipFile
จะทำ แต่สิ่งนี้จะกลายเป็นความเจ็บปวดครั้งใหญ่อย่างรวดเร็วเนื่องจากเรียกว่ามีสถานที่มากมาย เอาต์พุตของมันก็จะต้องถูกเยาะเย้ย ฯลฯ ฯลฯ การปรับโครงสร้างใหม่เพื่อพยายาม การทำให้สามารถเข้าถึงได้นี้อาจเป็นเรื่องที่น่าอึดอัดใจ เนื่องจากโค้ดที่ใช้ ZipFile
นั้นเป็นโค้ดภายใน และวิธีการสาธารณะไม่ได้สนใจมันมากนัก
ฉันรู้สึกว่ามีวิธีที่ JMockit อนุญาต (ให้อินสแตนซ์เฉพาะของวัตถุเมื่อมีการเรียกตัวสร้าง) แต่ฉันไม่สามารถเข้าใจได้ ไม่มีใครมีความคิดใด ๆ ?
แก้ไข: ฉันลองวิธีที่ @Rogerio แนะนำ แต่ฉันมีข้อผิดพลาดใหม่ นี่คือการตั้งค่าของฉัน:
final ZipFile test = new ZipFile("path/to/actual.zip");
new NonStrictExpectations() {
ZipFile zf;
{
zf.entries();
result = test.entries();
zf.getInputStream((ZipEntry) any);
result = new Delegate() {
InputStream getInputStream(ZipEntry entry) throws IOException {
return test.getInputStream(entry);
}
};
}
};
แต่ฉันได้รับการติดตามสแต็กต่อไปนี้:
java.lang.InternalError
at path.to.test.ExtractDataTest$1.<init>(ExtractDataTest.java:61)
at path.to.test.ExtractDataTest.setUp(ExtractDataTest.java:61)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
โดยที่บรรทัด 61 คือบรรทัด new NonStrictExpectations() {
ฉันอยากจะพูดว่า "แทนที่จะล้อเลียนวัตถุนี้ ให้แทนที่วัตถุประเภทเดียวกันนี้แทน" บางทีฉันอาจแสดงออกได้ไม่ดี
แก้ไข 2: ฉันคิดว่าฉันควรรวมหมายเลขเวอร์ชัน: การใช้ Eclipse 3.6.1 Java 1.6.0_26 JMockit 0.999.10