Java: Как мне высмеять метод поля, когда это поле не отображается?
Я использую Java 6, JUnit 4.8.1 и пишу консольное приложение. В моем приложении есть поле участника, которое не отображается...
public class MyApp {
...
private OpportunitiesService m_oppsSvc;
private void initServices() {
…
m_oppsSvc = new OpportunitiesServiceImpl(…);
}
...
}
Я хочу издеваться над таким поведением, что всякий раз, когда вызывается один метод из моей службы (например, m_oppsSvc.getResults()
), тот же результат всегда возвращается. Как мне это сделать? Нет никакого метода установки для поля. В настоящее время я работаю с Mockito 1.8.4. Можно ли сделать это с помощью Mockito или какой-либо другой фальшивой структуры?
Ответы
Ответ 1
Это то, что вы хотите:
@RunWith(MockitoJUnitRunner.class)
public class MyAppTest {
@Mock private OpportunitiesService mocked_m_oppsSvc;
@InjectMocks MyApp myApp;
@Test public void when_MyApp_uses_OpportunititesService_then_verify_something() {
// given
given( mocked_m_oppsSvc.whatever()).willReturn(...);
// when
myApp.isUsingTheOpportunitiesService(...);
// then
verify...
assertThat...
}
}
Использование: Mockito 1.9.0, Стиль BDD, FEST-Assert AssertJ.
Надеюсь, что помогает:)
Ответ 2
Вам следует подумать о попытках фальсифицировать личное поле smell. То есть признак того, что либо то, что вы пытаетесь сделать, либо неверно, либо что ваш код в настоящее время структурирован неправильно. Вам нужно только обмануть общедоступные методы или вложенные зависимости
В коде, который вы указали, вам следует рассмотреть возможность внедрения функции OpportunitiesService следующим образом:
public class MyApp {
...
private OpportunitiesService m_oppsSvc;
public MyApp(OpportunitiesService oppsSvc) {
this.m_oppsSvc = oppsSvc;
}
...
}
В своем тесте вы можете ввести макет следующим образом:
OpportunitiesService mockOpportunitiesService =
Mockito.mock(OpportunitiesService.class);
Mockit.when(mockOpportunitiesService.someMethod()).thenReturn(someValue);
MyApp app = new MyApp(mockOpportunitiesService);
Ответ 3
Учитывая, что вы уже используете mockito, почему бы просто не использовать отражение:
@RunWith(MockitoJUnitRunner.class)
public class MyApp {
@Mock
private OpportunitiesService m_oppsSvc;
private MyApp myApp;
@Before
public void before() throws Exception {
myApp = new MyApp();
Field f = MyApp.class.getDeclaredField("m_oppsSvc");
f.setAccessible(true);
f.set(myApp, m_oppsSvc);
}
}
Это немного уродливо, но это будет трюк. Обратите внимание, что это может быть не самый эффективный способ сделать это с Mockito, но он будет работать.
Там также Powermock, который должен позволить вам сделать это, также используя класс Whitebox. Я не буду разбираться во всех деталях Powermock, но здесь призыв ввести значение частного поля, которое должно быть макетным объектом:
Whitebox.setInternalState(myApp, "m_oppsSvc", m_oppsSvc);
Ответ 4
Вы можете легко сделать это с помощью JMockit:
public class MyAppTest
{
@Tested MyApp myApp;
@Test
public testSomething(final @Capturing OpportunitiesService mockService)
{
new NonStrictExpectations() {{
mockService.getResults(); result = asList("a", "b", "C");
// record other expectations, if needed
}};
myApp.whateverMethodIWantToTest();
new Verifications() {{
mockService.doSomething(anyInt);
// verify other expectations, if needed
}};
}
}
Даже если класс реализации OpportunitiesServiceImpl
не упоминается в тестовом коде, его экземпляры (любое их число) будут по-прежнему правильно издеваться.
Ответ 5
Как правило, вы должны использовать инъекцию зависимостей и передавать макет (тип OppportunitiesServiceImpl) через конструктор, отдельный сеттер или непосредственно к методу (getResults). Возможно, вам сначала понадобится извлечь интерфейс для OpportunitiesServiceImpl.
Ответ 6
Обычно это решается с помощью инъекции зависимостей. В обычном (производственном) режиме ваш контейнер инъекции зависимостей (например, Spring или Guice) будет вставлять экземпляр OpportunitiesService
в MyApp
через ваш конструктор или через сеттер.
Затем, когда вы тестируете, вы можете "ввести" экземпляр mock вручную, используя тот же аргумент setter или constructor.
Вместо того, чтобы делать
m_oppsSvc = new OpportunitiesServiceImpl(…);
Попробуйте выполнить OpportunitesService
через конструктор MyApp