Mock ReactiveSecurityContextHolder - java

how can I mock ReactiveSecurityContextHolder in the tests so it will be possible to get into the lambda flatmap
ReactiveSecurityContextHolder.getContext()
.map(SecurityContext::getAuthentication)
.flatMap(authentication -> {})

To mock Authentication held in the ReactiveSecurityContextHolder you need to use TestSecurityContextHolder and ReactorContextTestExecutionListener:
#RunWith(MockitoJUnitRunner.class)
public class ReactiveSecurityContextHolderTests {
#Mock
private Authentication authentication;
private TestExecutionListener reactorContextTestExecutionListener =
new ReactorContextTestExecutionListener();
#Before
public void setUp() throws Exception {
when(authentication.getPrincipal()).thenReturn("token");
TestSecurityContextHolder.setAuthentication(authentication);
reactorContextTestExecutionListener.beforeTestMethod(null);
}
#After
public void tearDown() throws Exception {
reactorContextTestExecutionListener.afterTestMethod(null);
}
//...tests...
}
Alternatively, you can use SpringRunner with #TestExecutionListeners annotation instead of MockitoJUnitRunner:
#RunWith(SpringRunner.class)
#TestExecutionListeners(ReactorContextTestExecutionListener.class)
public class ReactiveSecurityContextHolderTests {
private static Authentication authentication;
#BeforeClass
public static void setUp() throws Exception {
authentication = mock(Authentication.class);
when(authentication.getPrincipal()).thenReturn("token");
TestSecurityContextHolder.setAuthentication(authentication);
}
//...tests...
}
Find more information in the https://docs.spring.io/spring-security/site/docs/current/reference/html/test.html

You just need to add #WithMockUser("customUserName") on test.

Related

Mock Service without using constructor with Autowire but use Java method

I want to edit this code to use mock for services. This code is working fine:
#Service
public class BinCountryCheckFilterImpl {
private RiskFilterService riskFilterService;
private Terminals terminal;
#Autowired
public BinCountryCheckFilterImpl(Terminals terminal, RiskFilterService riskFilterService) {
this.terminal = terminal;
this.riskFilterService = riskFilterService;
}
public void validateBinCountryCheckFilter(Terminals terminal) throws JAXBException, JsonProcessingException {
List<RiskFilters> filter_list = riskFilterService.findRiskFiltersByTerminalIdAndType(terminal.getId(), "BinCountryCheckFilter");
}
}
JUnit test:
public class BinCountryCheckFilterImplTest {
#Test
public void testBinCountryCheckFilterImpl() throws JsonProcessingException, JAXBException {
//Arrange
RiskFilterService riskFilterService = Mockito.mock(RiskFilterService.class);
Terminals terminal = Mockito.mock(Terminals.class);
BDDMockito.given(
riskFilterService.findRiskFiltersByTerminalIdAndType(anyInt(), anyString()))
.willReturn(riskFiltersList);
int expectedInt = 11;
String expectedString = "BinCountryCheckFilter";
when(terminal.getId()).thenReturn(expectedInt);
BinCountryCheckFilterImpl binCountryCheckFilterImpl =
new BinCountryCheckFilterImpl(terminal, riskFilterService);
//Act
binCountryCheckFilterImpl.validateBinCountryCheckFilter();
//Assert
then(riskFilterService)
.should()
.findRiskFiltersByTerminalIdAndType(expectedInt, expectedString);
}
}
This code is NOT working:
#Service
public class BinCountryCheckFilterImpl {
#Autowired
#Qualifier("riskFilterService")
private RiskFilterService riskFilterService;
public Response validateBinCountryCheckFilter(Merchants merchant, Contracts contract, Terminals terminal,
PaymentTransaction message, HttpServletRequest request) throws JAXBException, JsonProcessingException {
...........
}
}
For some reason riskFilterService in null when I run the JUnit test. Is there some way to implement the service with the JUnit test properly?
In my case I don't want to call terminal from the constructor but from the Java method validateBinCountryCheckFilter(...) and riskFilterService as Autowired service.
The singleton bean BinCountryCheckFilterImpl cannot have the per-request value terminal as a field, i.e. as a parameter on the constructor when the code is deployed but it's working with the JUnit test. If the terminal value must be passed as a method parameter the JUnit code won't run.
Can you advice, please?
I'm assuming you're using JUnit4. The easiest way to do this is to use the MockitoJUnitRunner like this:
#RunWith(MockitoJUnitRunner.class)
public class BinCountryCheckFilterImplTest {
#InjectMocks
private BinCountryCheckFilterImpl binCountryCheckFilter;
#Mock
private RiskFilterService riskFilterService;
#Test
public void testBinCountryCheckFilterImpl() {
// test content
}
}
To use JUnit 5 you would change the #RunWith(MockitoJUnitRunner.class) to #ExtendWith(MockitoExtension.class). Of course anything else like #Test used would also need to be from JUnit 5. But, the Mockito #InjectMocks and #Mock annotations are the same as JUnit 4.
However, you can also use the Spring org.springframework.test.util.ReflectionTestUtils to set the field after you call the constructor with the mocked service. I prefer the first way over reflection, but this is closer to your current code.
riskFilterService = Mockito.mock(RiskFilterService.class);
binCountryCheckFilter = new BinCountryCheckFilterImpl();
ReflectionTestUtils.setField(binCountryCheckFilter, "riskFilterService", riskFilterService);
Change existing code to:
public class BinCountryCheckFilterImpl {
private final RiskFilterService riskFilterService;
public BinCountryCheckFilterImpl(#Qualifier("riskFilterService") RiskFilterService riskFilterService) {
this.riskFilterService = riskFilterService;
}
public void validateBinCountryCheckFilter(......) throws JAXBException, JsonProcessingException {
.........................
}
}

Mock field injection using Mockito

I Am new in JUnit PowerMockito. Am try to test a method inside a class.that class having an autowired filed.
Service Class
#Service
public class MyServiceRegistration
{
#Autowired
private AppConfig appConfig;
public void register() throws xception
{
//Do some thing
}
}
AppConfig
#Component
public class AppConfig
{
#Value("${spring.application.name}")
private String applicationName;
#Value("${server.port}")
private String serverPort;
//getter and setter
}
Test Class
#RunWith(PowerMockRunner.class)
#PrepareForTest({ AppConfig.class })
#PowerMockIgnore({ "javax.management.*" })
public class MyServiceRegistrationTest
{
#InjectMocks
MyServiceRegistration myServiceRegistration = new MyServiceRegistration();
#Mock
private AppConfig appConfig;
#Before
public void setUp() throws Exception
{
PowerMockito.when(AppConfig.getApplicationName()).thenReturn("SomeValue");
MockitoAnnotations.initMocks(this);
}
public final void testRegister() throws Exception
{
myServiceRegistration.register();
}
}
When I debug the code I can see that AppConfig is mocked. But the applicationName and serverPort fields are null.
debug screen
How can I solve this issue?
The problem with your code is that you inject your mocks twice.
First, they are injected by #RunWith(PowerMockRunner.class)
Second time, manually with MockitoAnnotations.initMocks(this);
You set the expectations on the first instance, and then overwrite the mocks, that is why the expectations aren't there.
To prove it
#Before
public void setUp() throws Exception
{
PowerMockito.when(appConfig.getApplicationName()).thenReturn("SomeValue");
AppConfig beforeInitMocks = appConfig;
MockitoAnnotations.initMocks(this);
AppConfig afterInitMocks = appConfig;
System.out.println("Same object?: " + (beforeInitMocks == afterInitMocks));
}
Note: I believe there is a typo in your post, you should have PowerMockito.when(appConfig.getApplicationName()) (with the lowercase appConfig)
Moved
PowerMockito.when(AppConfig.getApplicationName()).thenReturn("SomeValue");
to testRegister method. Now its working.

How to properly test a Spring Boot using Mockito

I never did a test and decided I would do my first.
I am using Spring Boot and by default the layout is as follows: https://zapodaj.net/c8b65f1644e95.png.html
The file that is created on startup looks like this
#RunWith(SpringRunner.class)
#SpringBootTest
public class RestWebServicesApplicationTests {
#Test
public void contextLoads() {
}
}
I do not change anything here, because I do not need it.
By contrast, I created a new class
public class CheckUserDataRestControllerTest {
#Mock
private UserService userService;
#InjectMocks
private CheckUserDataRestController checkUserDataRestController;
private MockMvc mockMvc;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.standaloneSetup(checkUserDataRestController).build();
}
#Test
public void textExistsUsername() throws Exception {
mockMvc
.perform(get("/checkUsernameAtRegistering")
.param("username", "jonki97"))
.andExpect(status().isOk());
}
}
To test the controller method, which should return the status OK.
#GetMapping("/checkUsernameAtRegistering")
public HttpEntity<Boolean> checkUsernameAtRegistering(#RequestParam String username) {
return ResponseEntity.ok().body(!userService.existsByUsername(username));
}
However, during the test, he throws me out
java.lang.AssertionError: Status
Expected :200
Actual :404
<Click to see difference>
at org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:54)
...
This is the tested controller: https://pastebin.com/MWW9YwiH
I did not make any special configurations because I did not find out that I needed to do something.
The error 404 means the Mock does not recognize your endpoint to test. The end point should be:
#Test
public void textExistsUsername() throws Exception {
mockMvc
.perform(get("/checkUserData/checkUsernameAtRegistering")
.param("username", "jonki97"))
.andExpect(status().isOk());
}
Hope this help.

Mocking exceptions with Mockito: Unexpected Exception error

This is the code of my service:
public class Service {
public Object serviceMethod() throws MyException {
#Autowired
Dao dao;
try {
return dao.dao_method();
} catch (ExceptionFromDaoMethod e) {
throw (new MyException());
}
}
}
I want to write a simple Unit Test; this is my test case:
#Mock
Dao dao;
#InjectMocks
Service service;
#Test(expected=MyException.class)
public void shouldReturnMyException throws MyException {
when(service.serviceMethod()).thenThrow(new MyException());
}
This test fails, because I have an Unexpected exception:
the expected exception is MyException but was
org.mockito.exception.base.MockitoException
Why? What is the solution?
Update
Thanks to #Maciej Kowalski I have noted that I was using the when condition versus a real class and not versus a mocked one.
So I added the annotation #Spy to the Service in the Unit Test. The code of the new test is:
#Mock
Dao dao;
#InjectMocks
#Spy
Service service;
#Before
MockitoAnnotations.initMocks(this);
#Test(expected=MyException.class)
public void shouldReturnMyException throws MyException {
doThrow(new MyException()).when(service.serviceMethod());
}
But now I have this problem:
the expected exception is MyException but was
You would have to #spy the Service as i assume you are using it as the instance with real implementation being invoked.
So try this:
#InjectMocks
#Spy
Service service;
#Test(expected=MyException.class)
public void shouldReturnMyException throws MyException {
doThrow(new MyException()).when(service).serviceMethod();
}
remember to start with doXX when mocking a #Spy.
Update
If you want to mock the dao call (which is a better test candidate..) you would have to make some changes if you only want to use plain Mockito.
If the dao is not your instance dependency then you will have to change your prod method:
public class Service {
public Object serviceMethod() throws MyException {
Dao dao = getDaoInstance();
try {
return dao.dao_method();
} catch (ExceptionFromDaoMethod e) {
throw (new MyException());
}
}
Dao getDaoInstance(){
return new Dao();
}
}
And your test class should me more or less like this:
#Mock
Dao dao;
#Spy
Service service;
#Test(expected=MyException.class)
public void shouldReturnMyException throws MyException {
doReturn(dao).when(service).getDaoInstance();
when(dao.dao_method()).thenThrow(new ExceptionFromDaoMethod());
service.serviceMethod();
}
Finally I found a solution: create unit tests for a Spring project is more challenging than I expected (at least using only Mockito Framework), so I found a solution using also some Spring Annotations
So this is my new working test:
#MockBean
Dao dao;
#Autowired
Service service;
#Test(expected=MyException.class)
public void shouldReturnMyException throws MyException {
when(dao.dao_method()).thenThrow(new ExceptionFromDaoMethod());
}

Mocking Spring bean's method behavior breaks aspects

I searched SO and found bunch of other questions that looked similar but not exactly, so I'll ask another one.
I have Spring application and say I created custom aspect (looking for CatchMe annotation) to log exceptions in a specific way. I want to test the aspect by mocking the behavior of one of my Spring #Service class's method so it throws exception when it is called. Then in another method, annotated with my custom annotation #CatchMe, I call the first method. What I expect to happen is the exception to get logged. Unfortunatelly the exception is thrown but the aspect is not triggered. So how can I make the aspect to get triggered in this test using Mockito?
Note: I've checked those (plus a bunch more):
Unit testing Spring #Around AOP methods
Spring Aspect not triggered in unit test
Spring: cannot inject a mock into class annotated with the #Aspect annotation
but most of them are Controller related and not Service related and I want to test only the service.
The Test
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {BeanConfig.class})
public class MyServiceTest {
#Autowired
#InjectMocks
private MyService service;
#Mock
private MyServiceDependency serviceDep;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
ReflectionTestUtils.setField(service, "serviceDep", serviceDep);
}
#Test
public void test() {
when(serviceDep.process()).thenAnswer(new Answer<Object>() {
#Override
public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
throw new Exception("Sample message.");
}
});
service.execute();
}
}
Services
#Service
public class MyService {
#Autowired
private MyServiceDependency serviceDep;
#CatchMe
public void execute() {
serviceDep.process();
}
}
#Service
public class MyServiceDependency {
public Object process() {
// may throw exception here
}
}
Configuration and Aspect
#Configuration
#EnableAspectJAutoProxy
#ComponentScan(basePackages = {"com.example.services"})
public class BeanConfig { .. }
#Aspect
#Component
public class CatchMeAspect {
#Around("#annotation(CatchMe)")
public Object catchMe(final ProceedingJoinPoint pjp) throws Throwable {
try {
pjp.proceed();
} catch (Throwable t) {
// fency log
}
}
}
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface CatchMe {}
EDIT: The functionality works but I want to verify it with the test.
Actually it is working as expected, however you are running in a side effect of proxy based AOP, especially class based proxies in this case.
Currently you are setting the field on the proxy and not on the actual object inside the proxy. Which is what you actually want. To obtain the actual instance use AopTestUtils.getUltimateTargetObject and then use that in the ReflectionTestUtils.setField method.
#Autowired
#InjectMocks
private MyService service;
#Mock
private MyServiceDependency serviceDep;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
MyService serviceToInject = AopTestUtils.getUltimateTargetObject(service);
ReflectionTestUtils.setField(serviceToInject, "serviceDep", serviceDep);
}
However I think that approach is wrong, when you start messing around like this there is a better way. Simply use Spring to inject the mock. Create a specific #Configuration class for this test case. Make it a internal public static class and for the dependency add a mocked #Bean.
#Configuration
#Import(BeanConfig.class)
public static class TestBeanConfig {
#Bean
public MyServiceDependency myServiceDependency() {
return Mockito.mock(MyServiceDependency.class);
}
}
Now in your test class you can simply #Autowire both beans and not need to use reflection or whatever to set dependencies.
#RunWith(SpringJUnit4ClassRunner.class)
public class MyServiceTest {
#Autowired
private MyService service;
#Autowired
private MyServiceDependency serviceDep;
#Test
public void test() {
when(serviceDep.process()).thenAnswer(new Answer<Object>() {
#Override
public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
throw new Exception("Sample message.");
}
});
service.execute();
}
}
Which will take care of the correct dependencies.
I had the same problem as #nyxz and this is intentional, see https://github.com/spring-projects/spring-boot/issues/7243.
Inspired by #M. Deinum following solution worked for me with Spring Boot 2.3.4.RELEASE and JUnit 5.
We will just provide a mocked bean without #MockedBean
#SpringBootTest
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
class MyServiceTest {
#Autowired
private MyService service;
#Test
public void test() {
service.execute();
}
static class TestBeanConfig {
#Bean
#Primary
public MyServiceDependency myServiceDependency() {
MyServiceDependency myServiceDependency = Mockito.mock(MyServiceDependency.class)
// Add behavior of mocked bean here
return myServiceDependency;
}
}
}

Categories