I am trying to wire up few tests.
My doubt is regarding execution of Order of TestExecutionListener
with parent class @Before
and @After
sequence of execution for currently running Test.
Example:
I have a class which setup some dummy user in table in test profile and deletes them. So i have created a base class for user related items. My Base class is as follows:
public abstract class BaseDataTest {
@Autowired
private UserRepository userRepository;
private TestUserGenerator testUserGenerator;
@Before
public void setUp() {
testUserGenerator = new TestUserGenerator(userRepository);
testUserGenerator.createTestUsers();
}
@After
public void cleanUp() {
testUserGenerator.deleteTestUsers();
testUserGenerator = null;
}
}
I now have 2 scenarios:
- Just insert user and later fetch from database that the count is more and users are present in test database.
- I have to insert test users and later check for a particular user and fetch all the users from
blocked
table from current logged in user.
For scenario 1 which works fine since there is no TestExecutionListener
annotation present on Test class so base class method setUp/cleanUp are called properly and my tests runs fine. My Test class is as below:
@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("test")
public class UserInsertTest extends BaseDataTest {
@Autowired
UserRepository userRepository;
@Test
public void testThatSystemHasUsers() {
Assert.assertNotSame(userRepository.count(), 0);
}
}
For scenario 2 which is not working as becuase i have TestExecutionListener
with WithSecurityContextTestExecutionListener
class as value, since my setUp method is not getting called and system has no users to prove authentication test is failing.
My BlockUserTest class is as below:
@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("test")
@TestExecutionListeners(value = {WithSecurityContextTestExecutionListener.class})
public class BlockUserTest extends BaseDataTest {
@Autowired
private AppUserDetailsService userDetailsService;
@Autowired
private BlockService blockRepository;
@Test
@WithUserDetails(value = "sabrinahuff@comstruct.com")
public void blockNoneReturnEmpty() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
User user = userDetailsService.loadUserByUsername(authentication.getName());
List<Block> blockedByMe = blockRepository.getBlockedByMe(user.getId(), PageRequest.of(0, Integer.MAX_VALUE));
Assert.assertNotNull(blockedByMe);
//as i have not blocked anyone yet in test
Assert.assertSame(blockedByMe.size(), 0);
}
}
I am getting
java.lang.IllegalStateException: Unable to create SecurityContext using @org.springframework.security.test.context.support.WithUserDetails(value=sabrinahuff@comstruct.com, userDetailsServiceBeanName=, setupBefore=TEST_METHOD)
at org.springframework.security.test.context.support.WithSecurityContextTestExecutionListener.createTestSecurityContext(WithSecurityContextTestExecutionListener.java:126)
at org.springframework.security.test.context.support.WithSecurityContextTestExecutionListener.createTestSecurityContext(WithSecurityContextTestExecutionListener.java:96)
at org.springframework.security.test.context.support.WithSecurityContextTestExecutionListener.beforeTestMethod(WithSecurityContextTestExecutionListener.java:62)
at org.springframework.test.context.TestContextManager.beforeTestMethod(TestContextManager.java:291)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
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.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
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.NullPointerException
at org.springframework.security.test.context.support.WithUserDetailsSecurityContextFactory.createSecurityContext(WithUserDetailsSecurityContextFactory.java:63)
at org.springframework.security.test.context.support.WithUserDetailsSecurityContextFactory.createSecurityContext(WithUserDetailsSecurityContextFactory.java:44)
at org.springframework.security.test.context.support.WithSecurityContextTestExecutionListener.createTestSecurityContext(WithSecurityContextTestExecutionListener.java:123)
... 24 more
java.lang.NullPointerException
at com.pkg.BaseDataTest.cleanUp(BaseDataTest.java: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: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.RunAfters.evaluate(RunAfters.java:33)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
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.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
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)
2019-05-14 13:21:23.104 INFO 17612 --- [ Thread-2] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
2019-05-14 13:21:23.108 INFO 17612 --- [ Thread-2] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2019-05-14 13:21:23.109 INFO 17612 --- [ Thread-2] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
2019-05-14 13:21:23.112 INFO 17612 --- [ Thread-2] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.
Which seems valid as inside principal is is null, because there are no test users present in db and hence loadUserByUsername is returned with null value.
Method from org.springframework.security.test.context.support.WithUserDetailsSecurityContextFactory
public SecurityContext createSecurityContext(WithUserDetails withUser) {
String beanName = withUser.userDetailsServiceBeanName();
UserDetailsService userDetailsService = this.findUserDetailsService(beanName);
String username = withUser.value();
Assert.hasLength(username, "value() must be non empty String");
UserDetails principal = userDetailsService.loadUserByUsername(username);
Authentication authentication = new UsernamePasswordAuthenticationToken(principal, principal.getPassword(), principal.getAuthorities());
SecurityContext context = SecurityContextHolder.createEmptyContext();
context.setAuthentication(authentication);
return context;
}
Keeping TestExecutionListener
and my test data generation how can i pass my block user test. Thank you!
Spring SecurityTest
@Test
@WithUserDetails(value = "brysonhensley@yahoo.com")
public void test() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
Assert.assertEquals(1, 1);
}
This seems to be working and upon debugging, my authentication object is populated with meaningful values, so UserDetailsService
bean name is picked up i think so.