2012-07-20 8 views
14

Używam Java 6, JUnit 4.8.1 i piszę aplikację konsolową. Moja aplikacja ma pole członka, który nie jest narażona ...Java: Jak wyśmiać metodę pola, gdy to pole nie jest odsłonięte?

public class MyApp { 
    ... 
    private OpportunitiesService m_oppsSvc; 

    private void initServices() { 
     … 
     m_oppsSvc = new OpportunitiesServiceImpl(…); 
    } 
    ... 
} 

chcę drwić zachowanie tak, że gdy jeden z moich usług metoda nazywa się (np m_oppsSvc.getResults()), ten sam wynik jest zawsze zwrócony. Jak mogę to zrobić? Nie ma metody ustawiającej dla tego pola. Obecnie pracuję z Mockito 1.8.4. Czy można to zrobić z Mockito lub z inną symulowaną strukturą?

+0

Nie możesz stworzyć metody setera? – jrad

+0

Możliwy duplikat [Jak testujesz metody prywatne] (http://programmers.stackexchange.com/questions/100959/how-do-you-unit-test-private-methods)? –

+0

Co próbujesz przetestować? to jest 'getResults()' public? Czy ma z nim powiązane pole prywatne, czy jest obliczane w czasie wykonywania? W zależności od odpowiedzi, możesz użyć "szpiega" lub szyderstwa może nie mieć z tym nic wspólnego i możesz użyć czegoś takiego jak 'org.springframework.test.util.ReflectionTestUtils', aby po prostu ustawić prywatne pole na wartość, którą chcesz. – jhericks

Odpowiedz

12

To jest to, co chcesz:

@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... 
    } 
} 

Zastosowanie: Mockito 1.9.0, BDD style, FEST-Assert AssertJ.

nadzieję, że pomoże :)

+0

@InjectMocks obsługuje tylko zastrzyk ustawiający. – Matt

+3

@InjectMocks może również wstrzykiwać prywatne pola. –

+1

Javadoc był niepoprawny, zawsze wspierał wtrysk pól prywatnych. Następnie zastrzyk ustawiający, a następnie wstrzyknięcie konstruktora w wersji 1.9.0. Sprawdź Javadoc InjectmMocks w wersji 1.9.0 http://docs.mockito.googlecode.com/hg/1.9.0/org/mockito/InjectMocks.html – Brice

-1

Generalnie powinieneś użyć iniekcji zależności i przekazać obiekt próbny (typu OppportunitiesServiceImpl) za pośrednictwem konstruktora, osobnego narzędzia ustawiającego lub bezpośrednio do metody (getResults). Może być konieczne najpierw wyodrębnienie interfejsu dla OpportunitiesServiceImpl.

-1

Zwykle rozwiązuje się to za pomocą zastrzyku zależności. W zwykłym trybie (produkcyjnym) twój kontener wstrzykiwania zależności (np. Spring lub Guice) wstawi instancję OpportunitiesService do MyApp poprzez twój konstruktor lub przez setera.

Następnie, podczas testowania można "wstrzyknąć" ręcznie symulowaną instancję przy użyciu tego samego argumentu ustawiającego lub konstruktora.

Zamiast robić

m_oppsSvc = new OpportunitiesServiceImpl(…); 

Spróbuj Przechodząc OpportunitesService się przez konstruktora MyApp „s

6

należy rozważyć próby mock prywatną pola smell. Oznacza to, że albo to, co próbujesz zrobić, jest albo niepoprawne, albo jego kod jest obecnie nieprawidłowo ustrukturyzowany. Trzeba tylko trzeba kpić metody publiczne lub wstrzyknięcia zależności

W kodzie dałeś należy rozważyć dożylne OpportunitiesService następująco:

public class MyApp { 
    ... 
    private OpportunitiesService m_oppsSvc; 

    public MyApp(OpportunitiesService oppsSvc) { 
     this.m_oppsSvc = oppsSvc; 
    } 
    ... 
} 

W testu można następnie wstrzyknąć mock następująco:

OpportunitiesService mockOpportunitiesService = 
    Mockito.mock(OpportunitiesService.class); 
Mockit.when(mockOpportunitiesService.someMethod()).thenReturn(someValue); 
MyApp app = new MyApp(mockOpportunitiesService); 
0

można łatwo zrobić z 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 
     }}; 
    } 
} 

Mimo że klasa implementacji OpportunitiesServiceImpl nie jest wymieniona w kodzie testowym, jej wystąpienia (dowolna ich liczba) będą nadal poprawnie wyśmiewane.

6

Zważywszy, że używasz już Mockito, dlaczego nie wystarczy użyć refleksji:

@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); 
    } 
} 

to trochę brzydki, ale będzie to rade.Zauważ, że nie jest to najskuteczniejszy sposób na zrobienie tego z Mockito, ale zadziała.

Istnieje również Powermock, który powinien umożliwić to również przy użyciu klasy Whitebox. Nie będę wchodził w szczegóły Powermock, ale tutaj jest wezwanie do wstrzyknięcia wartości pola prywatnego, co powinno być pozornym obiektem:

Whitebox.setInternalState(myApp, "m_oppsSvc", m_oppsSvc); 
Powiązane problemy