Может любой делать любые предложения о том, как лучше всего использовать EasyMock для ожидания вызова к Runtime.getRuntime().exec(xxx)
?
Я мог переместить вызов в метод в другом классе, который реализует интерфейс, но быть бы в идеальном мире.
interface RuntimeWrapper {
ProcessWrapper execute(String command) throws IOException;
}
interface ProcessWrapper {
int waitFor() throws InterruptedException;
}
Я задавался вопросом, были ли у кого-либо какие-либо другие предложения?
Ваш класс не должен вызывать Runtime.getRuntime ()
. он должен ожидать, что среда выполнения
будет установлена как его зависимость, и будет работать с ней. Затем в своем тесте вы можете легко предоставить макет и установить его как зависимость.
В качестве комментария я бы посоветовал посмотреть эту лекцию по объектно-ориентированному дизайну для проверки .
Обновление: Я не видел частного конструктора. Вы можете попробовать использовать инструментарий java-байт-кода , чтобы добавить еще один конструктор или сделать конструктор общедоступным, но это также может оказаться невозможным (если есть некоторые ограничения для этого класса).
Итак, ваш вариант - создать оболочку (как вы предложили в вопросе) и следовать подходу внедрения зависимостей.
Божо выше - это ИМО, правильное решение . Но это не единственное решение. Вы можете использовать PowerMock или JMockIt .
Использование PowerMock:
package playtest;
public class UsesRuntime {
public void run() throws Exception {
Runtime rt = Runtime.getRuntime();
rt.exec("notepad");
}
}
package playtest;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.legacy.PowerMockRunner;
import static org.powermock.api.easymock.PowerMock.*;
import static org.easymock.EasyMock.expect;
@RunWith(PowerMockRunner.class)
@PrepareForTest( { UsesRuntime.class })
public class TestUsesRuntime {
@Test
public void test() throws Exception {
mockStatic(Runtime.class);
Runtime mockedRuntime = createMock(Runtime.class);
expect(Runtime.getRuntime()).andReturn(mockedRuntime);
expect(mockedRuntime.exec("notepad")).andReturn(null);
replay(Runtime.class, mockedRuntime);
UsesRuntime sut = new UsesRuntime();
sut.run();
}
}
Райан Бейтс рассказал об этом в своей заставке «как добавить пользовательские маршруты, сделать некоторые параметры необязательными и добавить требования к другим параметрам». http://railscasts.com/episodes/70-custom-routes
-121--4268379-Да, HashSet идеально подходит для этого, так как он содержит одно значение для поиска в отличие от словаря, который требует ключ и значение.
-121--1874183- Возможно, вместо насмешек над Runtime.getRuntime () .exec ()
можно «поиздеваться» над сценарием/программой/и т.д. он должен был звонить.
Вместо передачи реальной последовательности командной строки в exec ()
запишите тестовый сценарий и выполните его вместо него. Сценарий может возвращать жестко закодированные значения, которые можно протестировать, как и издевательский класс.
Вот как вы могли бы сделать это с EasyMock 3.0 (и JUnit 4):
import org.junit.*;
import org.easymock.*;
import static org.easymock.EasyMock.*;
public final class EasyMockTest extends EasyMockSupport
{
@Test
public void mockRuntimeExec() throws Exception
{
Runtime r = createNiceMock(Runtime.class);
expect(r.exec("command")).andReturn(null);
replayAll();
// In tested code:
r.exec("command");
verifyAll();
}
}
Единственная проблема с выше теста является то, что время выполнения
потребности объектов, которые будут переданы кода тестируемой, который предотвращает его использованием Runtime.getRuntime ()
.
С JMockit , с другой стороны, следующий тест может быть написано, избегая этой проблемы:
import org.junit.*;
import mockit.*;
public final class JMockitTest
{
@Test
public void mockRuntimeExec() throws Exception
{
final Runtime r = Runtime.getRuntime();
new NonStrictExpectations(r) {{ r.exec("command"); times = 1; }};
// In tested code:
Runtime.getRuntime().exec("command");
}
}