I wrote a validation advisor in Kotlin which throws EntityValidationException when validation fails:
#Aspect
#Named
class ValidationAdvisor
#Inject constructor(val validator: EntityValidator) {
#Around(EVERY_SAVE_AND_UPDATE_TO_DATABASE)
fun validate(point: ProceedingJoinPoint): Any {
val result: List<ConstraintViolation<Any>> = validator.validate(getEntity(point))
if (isEntityValid(result))
return point.proceed()
throw EntityValidationException(
violationInfos = result as List<ConstraintViolationInfo>
)
}
private fun getEntity(point: ProceedingJoinPoint): Any {
return point.args[0]
}
private fun isEntityValid(result: List<ConstraintViolation<Any>>): Boolean {
return result.isEmpty()
}
companion object {
const val EVERY_SAVE_AND_UPDATE_TO_DATABASE = "execution(* beans.repositories.BaseRepository.save(..))"
}
}
I have a JUnit test (I write some parts in Kotlin and some in Java, to learn Kotlin in existing private project) which checks if exception is thrown:
#Test(expected = EntityValidationException.class)
public void test_WhenNameIsNotPresent_ThenExceptionIsThrown() throws Exception {
repository.save(/* entity to save */);
}
But then I saw that test fails because it throws UndeclaredThrowableException instead of EntityValidationException. Next, I read that Kotlin does not have checked exception. I think not only me have this problem - I am pretty sure that way of handling exceptions with #ControllerAdvice in Spring and Java also may be problematic when we decide to switch to Kotlin in production projects - because it rely on class which is thrown, and throwing UndeclaredThrowableException take away from us this possibility. Is there a way to by-pass this behaviour, to make sure that is possible to switch to Kotlin and old Spring way of handling exceptions (and unit tests for ValidationAdvisor) will remain unchanged? Thank you in advance for any help.
P.S. Github repo for project is available here: Playgroud for Kotlin, Spring Data etc..
P.S.2 Stacktrace:
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:237)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
Caused by: java.lang.reflect.UndeclaredThrowableException
at com.sun.proxy.$Proxy65.save(Unknown Source)
at ActorValidationTest.test_WhenNameIsNotPresent_ThenExceptionIsThrown(ActorValidationTest.java:26)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.ExpectException.evaluate(ExpectException.java:19)
... 26 more
Caused by: beans.validator.exceptions.EntityValidationException
at beans.aop.validation.ValidationAdvisor.validate(ValidationAdvisor.kt:23)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:629)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:618)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
... 37 more
For me looks like EntityValidationException (which I want to be thrown) causes UndeclaredThrowableException.
EntityValidationException Kotlin class code:
package beans.validator.exceptions
import beans.validator.constraintViolation.ConstraintViolationInfo
class EntityValidationException (val violationInfos: List<ConstraintViolationInfo>) : Exception() {
}
P.S.3 This also didn't work:
#Around(EVERY_SAVE_AND_UPDATE_TO_DATABASE)
#Throws(EntityValidationException::class)
fun validate(point: ProceedingJoinPoint): Any /* rest of code*/
P.S.4 Maybe the problem is that #Aspect is #Around Spring Data repository?
companion object {
const val EVERY_SAVE_AND_UPDATE_TO_DATABASE = "execution(* beans.repositories.BaseRepository.save(..))"
}
....
#NoRepositoryBean
public interface BaseRepository<ENTITY, IDENTIFIER extends Serializable>
extends JpaRepository<ENTITY, IDENTIFIER>, JpaSpecificationExecutor<ENTITY> {
}
You're trying to make the method save() or your repository throw a checked exception that it doesn't declare. So even if the aspect declares it, that can't work. You need to make your exception extend RuntimeException.
Related
I'm starting my first zats-test that follow the example at ZK.
But it returned this error:
java.lang.NoClassDefFoundError: org/zkoss/zats/ZatsException
This is my test case
public class LoginControllerTest {
#BeforeClass
public static void init() {
Zats.init("./WebContent");
}
#AfterClass
public static void end() {
Zats.end();
}
#After
public void after() {
Zats.cleanup();
}
#Test
public void test() {
DesktopAgent desktop = Zats.newClient().connect("/index.zul");
ComponentAgent button = desktop.query("button");
ComponentAgent label = desktop.query("label");
button.as(ClickAgent.class).click();
button.click();
Assert.assertEquals("Hello Mimic", label.as(Label.class).getValue());
}
}
I've received this:
java.lang.NoClassDefFoundError: org/zkoss/zats/ZatsException
at testing.LoginControllerTest.init(LoginControllerTest.java:16)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: java.lang.ClassNotFoundException: org.zkoss.zats.ZatsException
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 16 more
It looks like you're missing zats-common from your classpath. You haven't mentioned how you are handling library dependencies nor what version of zats you are using so it's hard to provide more help than that.
I am quite new to Mockito, though I have been running tests successfully before and today it just look so strange why mockito verify() method keeps telling me that a View method is required but not called even though I am sure Presenter method is calling it correctly. Here is my test code:
#Test
public void loadCallPlans_shouldUpdateAdapter() {
ArrayResponse<CallPlan> callPlans = new ArrayResponse<>();
callPlans.data = Arrays.asList(new CallPlan[]{new CallPlan(), new CallPlan()});
Single response = Single.just(callPlans);
when(callPlanRepository.getCallPlans()).thenReturn(response);
presenter.loadCallPlans("Today");
doAnswer((Answer<Void>) invocation -> {
Object[] args = invocation.getArguments();
System.out.println("View.updateCallPlans() called with arguments: " + java.util.Arrays.toString(args));
return null;
}).when(view).updateCallPlans(anyList());
verify(view).updateCallPlans(anyList());
}
I could confirm that the updateCallPlans() method is called because I am getting View.updateCallPlans() called with arguments: [[]] in the logcat. My complete log:
View.updateCallPlans() called with arguments: [[]]
Wanted but not invoked:
view.updateCallPlans(<any List>);
-> at CallPlansPresenterTest.loadCallPlans_should UpdateAdapter(CallPlansPresenterTest.java:69)
Actually, there were zero interactions with this mock.
Wanted but not invoked:
view.updateCallPlans(<any List>);
-> at CallPlansPresenterTest.loadCallPlans_should UpdateAdapter(CallPlansPresenterTest.java:69)
Actually, there were zero interactions with this mock.
at CallPlansPresenterTest.loadCallPlans_shouldUpdateAdapter(CallPlansPresenterTest.java:69)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:326)
at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:89)
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:97)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:310)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:131)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.access$100(PowerMockJUnit47RunnerDelegateImpl.java:59)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner$TestExecutorStatement.evaluate(PowerMockJUnit47RunnerDelegateImpl.java:147)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.evaluateStatement(PowerMockJUnit47RunnerDelegateImpl.java:107)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:82)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:298)
at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:87)
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:50)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:218)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:160)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:134)
at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34)
at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:136)
at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:121)
at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:57)
at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:59)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMainV2.main(AppMainV2.java:131)
If I make RxJava to return error as response, the test runs fine and View.setError() is correctly verified:
#Test
public void loadCallPlans_shouldShowError() {
String error = "Error";
Single response = Single.error(new Throwable(error));
when(callPlanRepository.getCallPlans()).thenReturn(response);
presenter.loadCallPlans("Today");
doAnswer((Answer<Void>) invocation -> {
Object[] args = invocation.getArguments();
System.out.println("View.setError() called with arguments: " + java.util.Arrays.toString(args));
return null;
}).when(view).setError(anyString());
verify(view).setError(error);
}
You are actually mocking a call to updateCallPlans
doAnswer((Answer<Void>) invocation -> {
Object[] args = invocation.getArguments();
System.out.println("View.updateCallPlans() called with arguments: " + java.util.Arrays.toString(args));
return null;
}).when(view).updateCallPlans(anyList());
}
So it will never invoke actual method.
Your verification should be inside answer invocation.
Just want to put it here in case someone is facing the same issue, I wasn't aware that AndroidSchedulers is a dirty class for mockito so I was using it directly in my presenter instead of creating a class that provides the needed schedulers via constructor. More explanation from here
I am writing a Junit unit test for a class and I am getting a java.lang.NullPointerException on the following line :
expect(lineConfigurationHandlerMock.getDeviceControlHandler().getDeviceParameters(item1)).andReturn(myDeviceParameters);
I think (i am not sure though) that it has something to do with the method (getDeviceControlHandler) that I am calling from within the mocked interface . Because I have added this line of code before the submentioned line:
Assert.assertNotNull(comLineConfigurationHandlerMock.getDeviceControlHandler());
And I am having the following error:
java.lang.AssertionError
I am stuck here and really need some help.
Thanks in Advance.
The thrown Exception:
java.lang.NullPointerException
at de.myproject.project.classTest.testGetParameters(classTest.java:123)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Here is the written test:
public class classTest {
// class under test
private classUnderTest classUnderTest;
private LineConfigurationHandler LineConfigurationHandlerMock;
private IMocksControl mocksControl;
List<DeviceParameter> myDeviceParameters;
DeviceParameter deviceParameter1;
DeviceParameter deviceParameter2;
#Before
public void setUp() throws Exception
{
mocksControl = EasyMock.createControl();
LineConfigurationHandlerMock = mocksControl.createMock(LineConfigurationHandler.class);
classUnderTest = new classUnderTest();
classUnderTest.setLineConfigurationHandler(LineConfigurationHandlerMock);
String item1 = "item1";
myDeviceParameters = new ArrayList<DeviceParameter>();
myDeviceParameters.add(deviceParameter1);
myDeviceParameters.add(deviceParameter2);
//Other stuff
}
#Test
public void testGetParameters()
{
expect(LineConfigurationHandlerMock.getDeviceControlHandler().getDeviceParameters(item1)).andReturn(myDeviceParameters);
mocksControl.replay();
//Some code .....
}
}
Here is the class under test :
public Class ClassUnderTest
{
#Inject
private LineConfigurationHandler lineConfigurationHandler;
public List<DeviceParameter> getDeviceParameters(String deviceId)
{
// Method implementation
}
#Required
public void setLineConfigurationHandler(LineConfigurationHandler lineConfigurationHandler)
{
this.lineConfigurationHandler = lineConfigurationHandler;
}
}
The interface in which the method is declared
public interface LineConfigurationHandler {
DeviceControlHandler getDeviceControlHandler();
//other Method declaration ...
}
DeviceControlHandler.class
public interface DeviceControlHandler extends Serializable{
List<DeviceParameter> getDeviceParameters(String deviceId);
//Other methods declaration ...
}
It is not simple, but very deterministic:
expect(lineConfigurationHandlerMock.getDeviceControlHandler().getDeviceParameters(item1)).andReturn(myDeviceParameters);
That line contains two items that can throw NPE:
A) lineConfigurationHandlerMock --> that object can be NULL
B) .getDeviceControlHandler() --> that method can return NULL
That's it. You can do simple printouts, like
System.out.println("mock: " + lineConfigurationHandlerMock)
System.out.println("handler: " + lineConfigurationHandlerMock.getDeviceControlHandler())
to figure which one is null. In your case, I think you are missing the setup for your lineConfigurationHandlerMock object: you have to tell it what to return when getDeviceControlHandler() is called.
In order to do that, you first have to create another mock object that should be returned when getDeviceControlHandler() is called. And that other mock, you have to configure for a call to getDeviceParameters()!
In other words: you can't specify like "mock.getA().doSomething()" - instead, you need another "mockedA" which you tell "doSomething()"; and then you tell "mock" that getA() should return "mockedA".
Update: I am not familiar with these annotations; I am used to use "EasyMock in a bare metal mode"; like
SomeObject innerMock = EasyMock.createMock(SomeObject);
expect(innerMock.doSomething()).andReturn("who cares");
SomeOther outerMock = EasyMock.createMock(SomeOther);
expect(outerMock.getDeviceControlHandler("sounds familiar")).andReturn(innerMock);
I use TestNG and I would like to run different times the same test and each time use specific data providers which will be used in a subset of test methods, in other words I would like to run the test class with different data without change the test itself.
I have got a problem creating the factory for the test class, here is my case:
#Test
public class MyTest {
#Factory
public Object[] createInstances() {
DataTest dataTest_1 = new DataTest("foo", true);
DataTest dataTest_2 = new DataTest("FOO", false);
Object[] result = new Object[]{
new MyTest(dataTest_1);
new MyTest(dataTest_2)
};
return result;
}
private final DataTest dataTest;
public MyTest(DataTest dataTest) {
this.dataTest = dataTest;
}
}
Error:
Configuring TestNG with: org.apache.maven.surefire.testng.conf.TestNGMapConfigurator#18e8568
org.apache.maven.surefire.util.SurefireReflectionException: java.lang.reflect.InvocationTargetException; nested exception is java.lang.reflect.InvocationTargetException: null
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)
Caused by: org.testng.TestNGException:
The factory method class MyTest.createInstances() threw an exception
at org.testng.internal.FactoryMethod.invoke(FactoryMethod.java:92)
at org.testng.internal.TestNGClassFinder.<init>(TestNGClassFinder.java:140)
at org.testng.TestRunner.initMethods(TestRunner.java:405)
at org.testng.TestRunner.init(TestRunner.java:231)
at org.testng.TestRunner.init(TestRunner.java:201)
at org.testng.TestRunner.<init>(TestRunner.java:150)
at org.testng.SuiteRunner$DefaultTestRunnerFactory.newTestRunner(SuiteRunner.java:523)
at org.testng.SuiteRunner.init(SuiteRunner.java:157)
at org.testng.SuiteRunner.<init>(SuiteRunner.java:111)
at org.testng.TestNG.createSuiteRunner(TestNG.java:1212)
at org.testng.TestNG.createSuiteRunners(TestNG.java:1199)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1053)
at org.testng.TestNG.run(TestNG.java:974)
at org.apache.maven.surefire.testng.TestNGExecutor.run(TestNGExecutor.java:77)
at org.apache.maven.surefire.testng.TestNGDirectoryTestSuite.execute(TestNGDirectoryTestSuite.java:110)
at org.apache.maven.surefire.testng.TestNGProvider.invoke(TestNGProvider.java:106)
... 9 more
Caused by: java.lang.NullPointerException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.testng.internal.FactoryMethod.invoke(FactoryMethod.java:80)
... 24 more
Moreover, DataTest component at the moment contains two parameters but it will contains much more parameters - to define the expected values - and a collection of data providers.
Eventually, if I use a String as parameter of the test class - just as a attempt - the test runs.
The problem is that you cannot instantiate a new instance of MyTest in order to call createInstances. So it becomes a chicken and egg problem. If you declare createInstances as a static method, it should work.
I've done a bunch of googling and messing around with my code but in the end I can't seem to figure out why the static mocking isn't working with PowerMock and Mockito.
I am trying to mock the LogCommand class' on() method in the JavaHg Library https://bitbucket.org/aragost/javahg which takes a javahg BaseRepository object as an argument and returns an instance of the LogCommand class. I want to have this return a mock log object so I can verify whether it's execute() command is called, but Mockito exceptions keep getting thrown.
Here's my code:
#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);
}
}
With this code I get stack trace:
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)
If I remove the matchers and use a BaseRepository object in the when instead of a matcher, it still throws an exception:
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)
Any help would be greatly appreciated--thanks!
Edit: As per #Ducan's request, here is some example code that is doing a very similar thing as the third party code I am using. Thanks!
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);
}
}
This does not work, but gives a different exception from above, which I'm guessing may be a root problem that are somehow hidden from the ones above:
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)
Progress? If I set it so on() calls a constructor that doesn't call another constructor this(), it doesn't give me this error.
Recently I had a similar issue trying to test my source code where static method from external class is used.
I solved this using EasyMock and 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 defers the loading of a certain package to the parent classloader. Static method from javax.management is used in this case:
ManagementFactory.getPlatformMBeanServer()
#PrepareForTest is used to configure both your class and external class.
Hope this ideas help you in your test case.
I believe the error is in the line:
LogCommand mockLogCommand = mock(LogCommand.class);
which appears to calling the mock(Class) method from the Mockito class (due to a static import), when it should be from PowerMockito.
Your PowerMock setup seems to be incomplete.
Include the following three dependencies:
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'
Add the following rule as a field to your unit test class:
#Rule public PowerMockRule rule = new PowerMockRule();
Additionally add the following annotation to your test class:
#PowerMockIgnore("org.mockito.*")
Then just follow the instructions on Mocking Static Methods.
MockitoAnnotations.initMocks(this);
do this on your setupMethod to enable anotations
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}