Я рассмотрел следующий вопрос, и он не совпадает с моим:
jMockit: как ожидать вызовов конструктора для объектов Mocked?
Этот вопрос похож, но ответ мне не помогает:
Как смоделировать конструктор по умолчанию для Класс свиданий с JMockit?
То, что я пытаюсь сделать, это издеваться над вызовом конструктора java.util.zip.ZipFile
, в частности, с аргументом java.io.File
. Я хотел бы, чтобы конструктор возвращал экземпляр другого ZipFile
, экземпляр которого я создам с помощью конструктора, который принимает только аргумент 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() {
.
Я действительно хочу сказать: «Вместо того, чтобы издеваться над этим объектом, замените этот другой объект того же типа». Может я плохо выразился.
EDIT2: я решил, что должен указать номера версий: Использование Eclipse 3.6.1 Java 1.6.0_26 JMockit 0.999.10