Я посмотрел на следующий вопрос, и он не совпадает с моим:
jMockit: как ожидать вызова конструктора для Mocked объектов?
Этот вопрос похож, но ответ мне не поможет:
Как смоделировать конструктор по умолчанию класса Date с помощью 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