Mockito swallows up stack trace? - java

Why does Mockito swallow up stack traces? For example, if I have a
public class Foo
{
public void foo()
{
bar();
}
public void bar()
{
baz();
}
public void baz()
{
throw new RuntimeException();
}
}
and a test such as
public class MockTest
{
#Test
public void test()
{
Mockito.spy(new Foo()).foo();
}
}
the exception thrown always looks like
java.lang.RuntimeException
at Foo.baz(Foo.java:17)
at MockTest.test(MockTest.java:11)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
** So, where is all the stuff between
Foo.baz(Foo.java:17)
MockTest.test(MockTest.java:11)
?
(The example provided here is a just a simplification -- I'm dealing with a lot more indirections, classes, and so forth. I can't have Mockito swallowing up the critical parts of a partial mock stack trace...)

YES, mockito cleans stacktraces !
The piece of code at work StackTraceFilter
There are different ways to disable that
Since Mockito 1.10.10, provide your own StackTraceCleanerProvider via the mockito extension mechanism (create a resource file mockito-extensions/org.mockito.plugins.StackTraceCleanerProvider with the qualified name of your implementation)
Override the cleansStackTrace method in a custom IMockitoConfiguration, look there for more information.

This is the magic of proxies.
The javadoc of [Mockito.spy()][1] states
Creates a spy of the real object. The spy calls real methods unless they are stubbed.
So spy() returns a mock object, which is a proxy. It is a sub class of Foo so it inherits the methods, but it wraps their execution in a interceptor method. This method has a try catch block which catches any exception thrown in the actual method invocation. The catch block then uses a ConditionalStackTraceFilter to clean up the stack trace. To do this, it uses a StackTraceFilter which in the comments of its filter(..) method states
/**
* Example how the filter works (+/- means good/bad):
* [a+, b+, c-, d+, e+, f-, g+] -> [a+, b+, g+]
* Basically removes all bad from the middle. If any good are in the middle of bad those are also removed.
*/
The call stack at the invocation of baz() is something like (super simplified)
at Foo.baz()
at FooPROXY.baz()
at Foo.bar()
at FooPROXY.bar()
at Foo.foo()
at FooPROXY.foo()
at MockTest.test()
All the PROXY stack trace elements, which are the proxies and the interceptors involved, and everything in between get removed. So you get the result you see.
Note that Junit also cleans it up so as not to show its internals.

Related

I am trying to mock a final java class using Mockito 2, class is getting mocked but I still get Unfinished Stubbing Exception

I have included MockMaker file as well- src\test\resources\mockito-extensions\org.mockito.plugins.MockMaker
The related code is as shown where SignatureValidator is final class-
mockValidator = mock(org.opensaml.xmlsec.signature.support.SignatureValidator.class);
mockSignature = mock(SignatureImpl.class);
mockCredential = mock(org.opensaml.security.credential.Credential.class);
#Test(expected = SamlSecurityException.class)
public void testGivenGoodProfileButInvalidSignature() throws SignatureException {
when(mockSamlToken.getSignature()).thenReturn(mockSignature);
when(mockSamlToken.getSAMLIssuerName()).thenReturn("fakeIssuerName");
doThrow(SignatureException.class).when(mockValidator).validate(mockSignature,mockCredential); // getting exception for this line
validator.validate(mockSamlToken);
}
Stack Trace-
java.lang.Exception: Unexpected exception, expected<com.cerner.cto.security.saml.SamlSecurityException> but was<org.mockito.exceptions.misusing.UnfinishedStubbingException>
at org.junit.internal.runners.statements.ExpectException.evaluate(ExpectException.java:28)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
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:538)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:760)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)
Caused by: org.mockito.exceptions.misusing.UnfinishedStubbingException:
Unfinished stubbing detected here:
-> at com.cerner.cto.security.saml.opensaml.SignatureValidatorTest.testGivenGoodProfileButInvalidSignature(SignatureValidatorTest.java:84)
E.g. thenReturn() may be missing.
Examples of correct stubbing:
when(mock.isOk()).thenReturn(true);
when(mock.isOk()).thenThrow(exception);
doThrow(exception).when(mock).someVoidMethod();
Hints:
1. missing thenReturn()
2. you are trying to stub a final method, which is not supported
3: you are stubbing the behaviour of another mock inside before 'thenReturn' instruction if completed
at org.opensaml.xmlsec.signature.impl.SignatureImpl.getXMLSignature(SignatureImpl.java:153)
SignatureValidator.validate(...) is a static method, not an instance method; so the statement in question:
doThrow(SignatureException.class).when(mockValidator).validate(mockSignature,mockCredential);
is equivalent to this:
doThrow(SignatureException.class).when(mockValidator);
SignatureValidator.validate(mockSignature,mockCredential);
and I think you can see why that's "unfinished stubbing".
(It's unfortunate that Java even lets you write instance.staticMethod(...) instead of ClassName.staticMethod(...), since the former is so misleading. Some compilers will warn you about this.)
For information about how to mock static methods, see this Stack Overflow question: Mocking static methods with Mockito.

Mockito: Zero interactions with this mock

I have a class that I would like to test.
#Configuration
#Import(EmailageConfiguration.class)
public class EmailageServiceConfiguration {
private static final String EMAILAGE_ACCOUNT_ID_CONFIG_KEY = "emailage.key";
private static final String EMAILAGE_API_KEY_CONFIG_KEY = "emailage.secret";
#Bean
public EmailageConfigHolder emailageConfigHolder(Environment env) {
final EmailageConfigHolder holder = new EmailageConfigHolder();
holder.setApiKey(env.getRequiredProperty(EMAILAGE_API_KEY_CONFIG_KEY));
holder.setAccountId(env.getRequiredProperty(EMAILAGE_ACCOUNT_ID_CONFIG_KEY));
return holder;
}
}
My test class is provided,
#RunWith(MockitoJUnitRunner.class)
public class EmailageServiceConfigurationTest {
#InjectMocks
private EmailageServiceConfiguration configuration;
#Mock
private Environment environment;
#Mock
private EmailageConfigHolder holder;
#Test
public void testEmailageConfigHolder() {
when(environment.getRequiredProperty(anyString())).thenReturn(anyString());
configuration.emailageConfigHolder(environment);
verify(holder, times(1)).setApiKey(anyString());
verify(holder, times(1)).setAccountId(anyString());
}
}
I get the error stack provided below,
Wanted but not invoked:
holder.setApiKey();
-> at com.ratepay.ella.service.config.EmailageServiceConfigurationTest.testEmailageConfigHolder(EmailageServiceConfigurationTest.java:48)
Actually, there were zero interactions with this mock.
Wanted but not invoked:
holder.setApiKey();
-> at com.ratepay.ella.service.config.EmailageServiceConfigurationTest.testEmailageConfigHolder(EmailageServiceConfigurationTest.java:48)
Actually, there were zero interactions with this mock.
at com.ratepay.ella.service.config.EmailageServiceConfigurationTest.testEmailageConfigHolder(EmailageServiceConfigurationTest.java:48)
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.InvokeMethod.evaluate(InvokeMethod.java:17)
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.mockito.internal.runners.DefaultInternalRunner$1.run(DefaultInternalRunner.java:79)
at org.mockito.internal.runners.DefaultInternalRunner.run(DefaultInternalRunner.java:85)
at org.mockito.internal.runners.StrictRunner.run(StrictRunner.java:39)
at org.mockito.junit.MockitoJUnitRunner.run(MockitoJUnitRunner.java:163)
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)
How do I correct the test?
Here:
final EmailageConfigHolder holder = new EmailageConfigHolder();
Mockito can't inject mocks into a local variable. The documentation is really clear about that:
Mockito will try to inject mocks only either by constructor injection, setter injection, or property injection in order and as described below.
Basically, by using new() within the body of your method you wrote hard to test code. Because with Mockito, you have zero options to control what new() will return in that method body.
Ways out of that:
make that "holder" a field of your class, then inject via that annotation, or via a constructor accepting a holder instance
pass an instance as parameter to the method
Or assuming that you can actually create a new Holder object within the production code within your unit test setup, and as you are returning that object, simply assert on the properties of the returned object. From that point of view, you do not need to using mocking here at all. Simply verify that the object coming back from that call has the expected properties!
Or, (not recommended) you could turn to PowerMock(ito) or JMockit, in order to gain control over that call to new(). But as said: better rework your code to be easy to test.
By the way: the real answer is that you step back and read a good tutorial about Mockito. You can't learn how to use such a framework by trial and error. Learn how to do it right with nice small examples, and then, when you understand how to connect the dots, then apply that to your own code!
While the other answer better fits with the situation, I'm not able to update the code and finally, wrote this test code.
#RunWith( MockitoJUnitRunner.class )
public class EmailageServiceConfigurationTest {
private static final String ACCOUNT_ID = "emailage.key";
private static final String API_KEY = "emailage.secret";
#InjectMocks
private EmailageServiceConfiguration configuration;
#Mock
private Environment environment;
#Test
public void testEmailageConfigHolder() {
configuration.emailageConfigHolder( environment );
verify( environment, times( 1 ) ).getRequiredProperty( API_KEY );
verify( environment, times( 1 ) ).getRequiredProperty( ACCOUNT_ID );
}
}

Mock final class in java using mockito library [duplicate]

This question already has answers here:
How to mock a final class with mockito
(28 answers)
Closed 5 years ago.
I have one class which is final, which has one method on which I want to perform certain action. Because of this I want to create object of final class. But I am unable to create it, following is my class.
public final class A {
private String name;
A(String name){
this.name = name;
}
public String getName(){
return name;
}
}
In my junit test case I want to create object of that class, like below
Class TestA{
#Test
public void testA(){
A a = mock(A.class);
when(a.getName()).then("ABC"); //on this line i am getting exception
}
}
I have tried it by using new keyword also, but not working. So is there anyway to create a mock object of final class?
Following exception I facing,
org.mockito.exceptions.base.MockitoException:
Cannot mock/spy class A
Mockito cannot mock/spy following:
- final classes
- anonymous classes
- primitive types
at com.rocket.map.resources.TestA.testA(TestA.java:46)
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.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)
try using this.
Use the #RunWith(PowerMockRunner.class) annotation at the class-level of the test case.
Use the #PrepareForTest(ClassWithFinal.class) annotation at the class-level of the test case.
Use PowerMock.createMock(ClassWithFinal.class) to create a mock object for all methods of this class (let's call it mockObject).
Use PowerMock.replay(mockObject) to change the mock object to replay mode.
Use PowerMock.verify(mockObject) to change the mock object to verify mode.
Also refer this answer - link
And Tutorial.
Both look easy to implement.
This is not possible with Mockito v1
Please look into this link. I think in advance version or powermockito you can do this.Powermockito example

NullPointerException when calling mocked method

I try to mock a final method (readChar of class DataInputStream):
MyClassTest
#RunWith(PowerMockRunner.class)
#PrepareForTest(DataInputStream.class)
public class MyClassTest {
#Test
public void testMyMethod() throws IOException {
DataInputStream mockStream = PowerMockito.mock(DataInputStream.class);
Mockito.when(mockStream.readChar()).thenReturn('a');
System.out.println(mockStream.readChar()); // OK (print 'a')
Assert.assertEquals('a', MyClass.myMethod(mockStream));
}
}
MyClass
public class MyClass {
public static char myMethod(DataInputStream dis) throws IOException {
return dis.readChar(); // NPE raises
}
}
It works when calling the mocked method in testMyMethod() but in myMethod() NullPointerException raises, why?
EDIT :
The complete failure trace :
java.lang.NullPointerException
at java.io.DataInputStream.readChar(Unknown Source)
at test.test.MyClass.myMethod(MyClass.java:8)
at test.test.MyClassTest.testMyMethod(MyClassTest.java:23)
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.internal.runners.TestMethod.invoke(TestMethod.java:59)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:310)
at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:79)
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:87)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:294)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:282)
at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:77)
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:42)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:207)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:146)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:120)
at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:27)
at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:37)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:122)
at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:104)
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.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
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:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
First this code is a mock antipattern : Don't mock types you don't own! (see this answer on StackOverflow)
Second, DataInputStream is a class of the JDK PowerMock cannot use the same hacky classloader that modifies byte code.
For that there's a solution and two possible tricks :
use the interface
encapsulate the call in a class that you own, then prepare this class instead, documented here at google code, or even better make your own mockable class (without the need of powermock)
use an agent, documented here at google code
The first option is clearly the very best, and the first two options also allows one to avoid this mock antipattern.
DataInputStream is a 'system' class from JVM which is probably already loaded by JVM.
#PrepareForTest would have to remove final modifier from the methods (to be able to mock), but it can't do so for already-loaded classes (HotSpot JVM doesn't support class signature changes for already-loaded classes), and this is probably why you get this exception.
Luckily there's also DataInput interface implemented by DataInputStream - maybe you can try mocking not DataInputStream but DataInput, for this you don't even need PowerMock, just Mockito.

Can't get elements from database twice

I'm testing DAO layer in Spring MVC + Hibernate + HSQLDB and I'm not able to load playlist twice from database.
I don't know why I get size of List as 0. Method testSavePlaylist is successful, but method test_getPlaylistById fails. When I test only one method it's working great.
Error Trace:
java.lang.AssertionError: expected:<2> but was:<0>
at org.junit.Assert.fail(Assert.java:88)
at org.junit.Assert.failNotEquals(Assert.java:743)
at org.junit.Assert.assertEquals(Assert.java:118)
at org.junit.Assert.assertEquals(Assert.java:555)
at org.junit.Assert.assertEquals(Assert.java:542)
at adrian.example.musicplayer.dao.music.PlayListImplDaoTest.test_getPlaylistById(PlayListImplDaoTest.java:44)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:233)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:87)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:176)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Junit Class
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration
#Transactional
public class PlayListImplDaoTest {
#Autowired
PlayListDao playlistDao;
private static boolean setUpIsDone = false;
#Before
public void setUp() throws Exception {
if(setUpIsDone) {
return;
}
this.playlistDao.savePlaylistForJunit();
setUpIsDone = true;
}
#Test
public void test_getPlaylistById() throws InterruptedException {
List<Playlist> testedPlaylist = (List<Playlist>) this.playlistDao.getPlaylistById(1);
assertEquals(2, testedPlaylist.size());
}
#Test
public void testSavePlaylist() throws InterruptedException {
this.playlistDao.savePlaylist(1, "TestPlaylist2");
List<Playlist> testedPlaylist2 = (List<Playlist>) this.playlistDao.getPlaylistById(1);
assertEquals(2, testedPlaylist2.size());
}
}
I believe, the default behavior for transactional JUnit tests in spring is to rollback after each test. Therefore, the once off DB population you do in setUp() gets rolled back after the first test, leading to the 2nd test failing because the database is now empty.
You could reverse this behavior by annotating the test class with #TransactionConfiguration(defaultRollback=false).
However, it can be considered a bad practice to have stateful tests, whereby data is persisted after one test, with the potential to impact the results of the next and to yield different results based on the execution order.
Instead, you may be better off removing the "if" from your setUp() and re-populating your DB anew for each test pass.
You annotated your class as #Transactional, what means that every #Test method will be executed within a transaction. Method annotated with #Before is executed before each of test method, but within the same transaction as the test method. Be aware of the fact that #TransactionConfiguration(defaultRollback = true) is default for test environment. So if you run your tests one of many possible scenarios is:
a new transaction is open
whole setUp() is executed what means that some test data are created using this.playlistDao.savePlaylistForJunit() and after that the flag setUpIsDone is set to true
testSavePlaylist() is executed succesfully as there are test data available
the transaction is rolled back what means that test data created by this.playlistDao.savePlaylistForJunit() is gone
a new transaction is open
setUp method is early returned as setUpIsDone is true at this point
test_getPlaylistById() is executed but there is no test data available
the transaction is rolled back
For more information look at the section Spring Testing Annotations of the Spring Reference Documentation

Categories