2015-02-25 7 views
2

Я сделал кучу поисковых запросов и возился с моим кодом, но, в конце концов, я не могу понять, почему статическое издевательство не работает с PowerMock и Mockito.PowerMock Статический метод stubbing, похоже, не работает

Я пытаюсь дразнить LogCommand класса on() метод в JavaHg библиотека https://bitbucket.org/aragost/javahg, которая принимает javahg BaseRepository объекта в качестве аргумента и возвращает экземпляр класса LogCommand. Я хочу, чтобы это возвращало ложный объект журнала, поэтому я могу проверить, вызвана ли его команда execute(), но исключения Mockito продолжают бросаться.

Вот мой код:

@RunWith(PowerMockRunner.class) 
@PrepareForTest(LogCommand.class) 
public class MyRepositoryTest { 

    private BaseRepository mockHgRepo; 
    private MyRepository myRepository; 

    @Before 
    public void before() { 
     mockHgRepo = mock(BaseRepository.class); 
     PowerMockito.mockStatic(LogCommand.class); 
    } 

    @Test 
    public void staticMockTest() throws IOException { 
     LogCommand mockLogCommand = mock(LogCommand.class); 
     when(LogCommand.on(any(BaseRepository.class))).thenReturn(mockLogCommand); // Problem Line! 
     myRepository = new MyRepository(mockHgRepo); 
    } 
} 

С помощью этого кода я получаю трассировку стека:

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: 
Misplaced argument matcher detected here: 

-> at com.mycompany.repository.config.MyRepositoryTest.getNextTagNumberTest(MyRepositoryTest.java:39) 

You cannot use argument matchers outside of verification or stubbing. 
Examples of correct usage of argument matchers: 
    when(mock.get(anyInt())).thenReturn(null); 
    doThrow(new RuntimeException()).when(mock).someVoidMethod(anyObject()); 
    verify(mock).someMethod(contains("foo")) 

Also, this error might show up because you use argument matchers with methods that cannot be mocked. 
Following methods *cannot* be stubbed/verified: final/private/equals()/hashCode(). 

    at com.mycompany.myRepository.config.MyRepositoryTest.staticMockTest(MyRepositoryTest.java:39) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68) 
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:312) 
    at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:88) 
    at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:96) 
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:296) 
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit49RunnerDelegateImpl$PowerMockJUnit49MethodRunner.executeTestInSuper(PowerMockJUnit49RunnerDelegateImpl.java:116) 
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit49RunnerDelegateImpl$PowerMockJUnit49MethodRunner.executeTest(PowerMockJUnit49RunnerDelegateImpl.java:77) 
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:284) 
    at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:86) 
    at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:49) 
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:209) 
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:148) 
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:122) 
    at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:33) 
    at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:45) 
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:120) 
    at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:101) 
    at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53) 
    at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:53) 
    at org.junit.runner.JUnitCore.run(JUnitCore.java:160) 
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:74) 
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:211) 
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:67) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134) 

Если я удалить matchers и использовать BaseRepository объект в когда вместо согласовани, это еще исключение:

org.mockito.exceptions.misusing.MissingMethodInvocationException: 
when() requires an argument which has to be 'a method call on a mock'. 
For example: 
    when(mock.getArticles()).thenReturn(articles); 

Also, this error might show up because: 
1. you stub either of: final/private/equals()/hashCode() methods. 
    Those methods *cannot* be stubbed/verified. 
2. inside when() you don't call method on mock but on some other object. 
3. the parent of the mocked class is not public. 
    It is a limitation of the mock engine. 

-> at com.mycompany.repository.config.MyRepositoryTest.getNextTagNumberTest(MyRepositoryTest.java:39) 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68) 
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:312) 
at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:88) 
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:96) 
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:296) 
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit49RunnerDelegateImpl$PowerMockJUnit49MethodRunner.executeTestInSuper(PowerMockJUnit49RunnerDelegateImpl.java:116) 
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit49RunnerDelegateImpl$PowerMockJUnit49MethodRunner.executeTest(PowerMockJUnit49RunnerDelegateImpl.java:77) 
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:284) 
at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:86) 
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:49) 
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:209) 
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:148) 
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:122) 
at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:33) 
at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:45) 
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:120) 
at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:101) 
at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53) 
at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:53) 
at org.junit.runner.JUnitCore.run(JUnitCore.java:160) 
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:74) 
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:211) 
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:67) 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134) 

Любая помощь была бы принята с благодарностью - спасибо!


Edit: По просьбе @ Ducan, вот пример кода, который делает очень похожую вещь, как код третьей стороны, я использую. Благодаря!

public class TestRepository { 

    private String repoLocation; 

    public static TestRepository on (String repoLocation) { 
     return new TestRepository(repoLocation); 
    } 

    public TestRepository(String repoLocation, String extraflags) { 
     this.repoLocation = repoLocation; 
    } 

    private TestRepository (String repoLocation) { 
     this(repoLocation, "default flags"); 
    } 
} 



@RunWith(PowerMockRunner.class) 
@PrepareForTest(TestRepository.class) 
public class MyRepositoryTest { 

    @Test 
    public void staticMockTest() throws IOException { 
     PowerMockito.mockStatic(TestRepository.class); 
     TestRepository mockRepository = mock(TestRepository.class); 
     when(TestRepository.on(anyString())).thenReturn(mockRepository); 
    } 
} 

Это не работает, но дает другое исключение из выше, что я предполагаю, что может быть корень проблемы, которые так или иначе скрыты от тех, выше:

java.lang.VerifyError: Inconsistent stackmap frames at branch target 51 in method com.mycompany.repository.config.TestRepository.<init>(Ljava/lang/String;)V at offset 41 
    at java.lang.Class.getDeclaredConstructors0(Native Method) 
    at java.lang.Class.privateGetDeclaredConstructors(Class.java:2413) 
    at java.lang.Class.getDeclaredConstructors(Class.java:1855) 
    at org.mockito.internal.creation.jmock.ClassImposterizer.setConstructorsAccessible(ClassImposterizer.java:75) 
    at org.mockito.internal.creation.jmock.ClassImposterizer.imposterise(ClassImposterizer.java:70) 
    at org.powermock.api.mockito.internal.mockcreation.MockCreator.createMethodInvocationControl(MockCreator.java:110) 
    at org.powermock.api.mockito.internal.mockcreation.MockCreator.mock(MockCreator.java:60) 
    at org.powermock.api.mockito.PowerMockito.mockStatic(PowerMockito.java:70) 
    at com.mycompany.MyRepositoryTest.staticMockTest(MyRepositoryTest.java:30) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68) 
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:312) 
    at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:88) 
    at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:96) 
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:296) 
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit49RunnerDelegateImpl$PowerMockJUnit49MethodRunner.executeTestInSuper(PowerMockJUnit49RunnerDelegateImpl.java:116) 
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit49RunnerDelegateImpl$PowerMockJUnit49MethodRunner.executeTest(PowerMockJUnit49RunnerDelegateImpl.java:77) 
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:284) 
    at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:86) 
    at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:49) 
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:209) 
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:148) 
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:122) 
    at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:33) 
    at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:45) 
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:120) 
    at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:101) 
    at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53) 
    at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:53) 
    at org.junit.runner.JUnitCore.run(JUnitCore.java:160) 
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:74) 
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:211) 
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:67) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134) 

Прогресс? Если я его установил, то on() вызывает конструктор, который не вызывает другой конструктор this(), он не дает мне эту ошибку.

+0

Вы можете упростить пример кода, так что не полагаться на внешние классы мы не имеем? Это поможет нам экспериментировать, чтобы найти решение. –

+0

Для последнего исключения «java.lang.VerifyError: несогласованные фреймы стека» решение заключается в добавлении -XX: -UseSplitVerifier в конфигурацию времени выполнения JVM. См. Этот вопрос stackoverflow для того же: http://stackoverflow.com/questions/15253173/how-safe-is-it-to-use-xx-usesplitverifier – sam100rav

ответ

1

Недавно у меня была аналогичная проблема, пытающаяся проверить исходный код, где используется статический метод из внешнего класса. Я решил это с помощью EasyMock и PowerMock.

@RunWith(PowerMockRunner.class) 
@PowerMockIgnore("javax.management.*") 
@PrepareForTest({ManagementFactory.class, InstallerAppCheckerManagerImpl.class}) 
public class AppCheckerTester { 

    @Test 
    public void testBeanManager() throws Exception { 
    // this action is required by PowerMock 
    PowerMock.mockStatic(ManagementFactory.class); 

    // here is where a mock for static method is defined 
    MBeanServer server = PowerMock.createMock(MBeanServer.class); 
    EasyMock.expect(ManagementFactory.getPlatformMBeanServer()).andReturn(server); 

    // ... 
    PowerMock.replayAll(); 

    /* some test logic between replay and verify. */ 

    PowerMock.verifyAll(); 
    } 

} 

@PowerMockIgnore откладывает загрузку определенного пакета к родительскому загрузчику. Статический метод из javax.management используется в данном случае:

ManagementFactory.getPlatformMBeanServer() 

@PrepareForTest используется для настройки как вашего класса и внешний класса.

Надеюсь, что эта идея поможет вам в вашем тестовом случае.

1

Я считаю, что ошибка в строке:

LogCommand mockLogCommand = mock(LogCommand.class); 

, который, как представляется, вызывая mock(Class) метод из Mockito класса (из-за статический импорт), когда оно должно быть от PowerMockito.

+0

Спасибо за ответ. Я попытался использовать PowerMockito.mock() специально здесь, и, похоже, не исправил его. Этот макет LogCommand является обычным манеклом объекта, который я пытаюсь получить из метода static on(), который в основном является статическим заводским методом. – creftos

0

Ваш PowerMock установка кажется неполной.

  1. Включить следующие три зависимости:

    testCompile 'org.powermock:powermock-api-mockito:1.6.2'

    testCompile 'org.powermock:powermock-module-junit4-rule:1.6.2'

    testCompile 'org.powermock:powermock-classloading-xstream:1.6.2'

  2. Добавьте следующее правило в качестве поля для вашего устройства тестового класса:

    @Rule public PowerMockRule rule = new PowerMockRule();

  3. Дополнительно добавьте следующую аннотацию к своему тестовому классу:

    @PowerMockIgnore("org.mockito.*")

Затем следуйте инструкциям на Mocking Static Methods.

0
MockitoAnnotations.initMocks(this); 

сделать это на setupMethod, чтобы включить АННОТАЦИИ

@Before 
    public void setUp() throws Exception { 
     MockitoAnnotations.initMocks(this); 
    } 
Смежные вопросы