Error while defining a Spring component - java

I'd like to define a my own component by using Spring.
Below there is my code:
MyPasswordEncoderConfig:
#Configuration
#ComponentScan(basePackages = { "my.package" })
public class CryptoConfig {
#Bean
public PasswordEncoder getPasswordEncoder() {
return new BCryptPasswordEncoder();
}
}
MyPasswordEncoder:
#Component
public class MyPasswordEncoder {
#Autowired
private PasswordEncoder passwordEncoder; // Defined in Spring Security.
public String encode(String plainTextPassword) {
return passwordEncoder.encode(plainTextPassword);
}
public boolean matches(String encodedPasswordA, String encodedPasswordB) {
return passwordEncoder.matches(encodedPasswordA, encodedPasswordB);
}
}
MyPasswordEncoderTest:
#ContextConfiguration(classes = {MyPasswordEncoder.class, MyPasswordEncoderConfig.class})
#RunWith(SpringJUnit4ClassRunner.class)
public class MyPasswordEncoderTest {
#Mock
private PasswordEncoder passwordEncoder;
#InjectMocks
#Autowired
private MyPasswordEncoder myPasswordEncoder;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
}
#Test
public void testPasswordMatching() {
String plainTextPassword = "ABCdef123###";
String encodedPassword = myPasswordEncoder.encode(plainTextPassword);
assertTrue(myPasswordEncoder.matches(plainTextPassword, encodedPassword));
}
}
When I run the test, it fails. Checking the result by using the standard output, the passwordEncoder.encode(plainTextPassword); returns a null value.
What am I doing wrong?
UPDATE:
The problem is regarding the PasswordEncoder interface. If I replace it with BCryptPasswordEncoder, the test works fine.

From what I gather from your test code, you actually want to test the functionality of MyPasswordEncoder. So why use mocks?
Why not just use #Autowired for both PasswordEncoder and MyPasswordEncoderlike in the following code:
#ContextConfiguration(classes = {MyPasswordEncoder.class, MyPasswordEncoderConfig.class})
#RunWith(SpringJUnit4ClassRunner.class)
public class MyPasswordEncoderTest {
#Autowired
private PasswordEncoder passwordEncoder;
#Autowired
private MyPasswordEncoder myPasswordEncoder;
#Test
public void testPasswordMatching() {
String plainTextPassword = "ABCdef123###";
String encodedPassword = myPasswordEncoder.encode(plainTextPassword);
assertTrue(myPasswordEncoder.matches(plainTextPassword, encodedPassword));
}
}
If you do not want to write a spring integration test but a simple unit test and do not want to refactor your code, you could write the following:
public class MyPasswordEncoderTest {
private PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
private MyPasswordEncoder myPasswordEncoder = new MyPasswordEncoder();
#Before
public void init() {
ReflectionTestUtils.setField(myPasswordEncoder, "passwordEncoder", passwordEncoder);
}
#Test
public void testPasswordMatching() {
String plainTextPassword = "ABCdef123###";
String encodedPassword = myPasswordEncoder.encode(plainTextPassword);
assertTrue(myPasswordEncoder.matches(plainTextPassword, encodedPassword));
}
}
An even better solution (which ditches the use of Spring ReflectionTestUtils) is to refactor MyPasswordEncoder like so:
#Component
public class MyPasswordEncoder {
private final PasswordEncoder passwordEncoder; // Defined in Spring Security.
#Autowired
public MyPasswordEncoder(PasswordEncoder passwordEncoder) {
this.passwordEncoder = passwordEncoder;
}
public String encode(String plainTextPassword) {
return passwordEncoder.encode(plainTextPassword);
}
public boolean matches(String encodedPasswordA, String encodedPasswordB) {
return passwordEncoder.matches(encodedPasswordA, encodedPasswordB);
}
}
Then the unit test would become:
public class MyPasswordEncoderTest {
private MyPasswordEncoder myPasswordEncoder = new MyPasswordEncoder(new BCryptPasswordEncoder());
#Test
public void testPasswordMatching() {
String plainTextPassword = "ABCdef123###";
String encodedPassword = myPasswordEncoder.encode(plainTextPassword);
assertTrue(myPasswordEncoder.matches(plainTextPassword, encodedPassword));
}
}

The issue here is that because of #InjectMocks, the actual PasswordEncoder that is being injected is the #Mock
#Mock
private PasswordEncoder passwordEncoder;
not the one in your #Configuration class. (Actually, both are injected, but the mock is injected last, so that's the one that is used.) You can verify this with (if the field was visible).
System.out.println(MyPasswordEncoder.passwordEncoder.getClass());
would print something like
class com.spring.PasswordEncoder$$EnhancerByMockitoWithCGLIB$$7d70b580
// pay attention to ^ this part ^
Mocks are typically implemented to return null for reference types, 0 for numerical primitives, and false for boolean.

Related

Problem with password encoder in the test

When trying to test a method, I'm getting a NullPointerException in this line of code:
when(webConfig.passwordEncoder().encode(any())).thenReturn(userUpdated.getPassword());
java.lang.NullPointerException: Cannot invoke "org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder.encode(java.lang.CharSequence)" because the return value of "com.example.paymybuddy.security.WebConfig.passwordEncoder()" is null
I have provided a mock of WebConfig class but it looks like still missing something. Thank you for your help in advance.
My code:
#ExtendWith(MockitoExtension.class)
public class Test {
#Mock
SecurityService securityService;
#Mock
IUserRepository userRepository;
#Mock
WebConfig webConfig;
#InjectMocks
UserService userService;
#Test
public void updateProfileTest() {
UserProfileDTO userDTO = new UserProfileDTO();
userDTO.setEmail("john#simons");
userDTO.setFirstName("John");
userDTO.setLastName("Simons");
userDTO.setPassword("pass");
userDTO.setConfirmPassword("pass");
User userForUpdate = new User();
userForUpdate.setFirstName("Joo");
userForUpdate.setLastName("Sim");
userForUpdate.setBalance(242.20);
userForUpdate.setEmail("john#simons");
userForUpdate.setPassword("pass");
userForUpdate.setRole("ROLE_USER");
User userUpdated = new User();
userUpdated.setFirstName("John");
userUpdated.setLastName("Simons");
userUpdated.setBalance(242.20);
userUpdated.setEmail("john#simons");
userUpdated.setPassword("pass");
userUpdated.setRole("ROLE_USER");
when(userRepository.findByEmail(any())).thenReturn(userForUpdate);
when(webConfig.passwordEncoder().encode(any())).thenReturn(userUpdated.getPassword());
when(userRepository.save(any())).thenReturn(userUpdated);
User test = userService.updateProfile(userDTO);
assertEquals("john#simons",test.getEmail());
}
}
#Service
public class UserService {
#Autowired
private SecurityService securityService;
#Autowired
private IUserRepository userRepository;
#Autowired
private WebConfig webConfig;
public User updateProfile (UserProfileDTO userProfileDTO) {
User user = userRepository.findByEmail(securityService.getLoggedUser());
user.setFirstName(userProfileDTO.getFirstName());
user.setLastName(userProfileDTO.getLastName());
user.setEmail(securityService.getLoggedUser());
if(!userProfileDTO.getConfirmPassword().equals(userProfileDTO.getPassword())){
throw new PasswordException("Password confirmation not match");
}
user.setPassword(webConfig.passwordEncoder().encode(userProfileDTO.getPassword()));
return userRepository.save(user);
}
}
#Configuration
public class WebConfig implements WebMvcConfigurer {
#Bean
public BCryptPasswordEncoder passwordEncoder() {
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
return bCryptPasswordEncoder;
}
#Bean
RequestRejectedHandler requestRejectedHandler() {
return new HttpStatusRequestRejectedHandler();
}
}
when(webConfig.passwordEncoder().encode(any())).thenReturn(userUpdated.getPassword());
This line is the problem (or more broadly your design but more on that later). webConfig is a mock, which means it will intercept all method calls and excert the registered behavior or the default if none. webConfig.passwordEncoder() is the first call on yuor mock and you haven't told the mock what to do, hence it will do the default which is to return null. You go then on by mocking the encode call on the return value, which will fail.
You should either tell Mockito to do something else by default (#Mock(answer = Answers.RETURNS_DEEP_STUBS instead of plain #Mock) or explicitly mock the call to webConfig.passwordEncoder() and return a mocked PasswordEncoder and then mock behavior on that for encode.
However the fact that you inject the WebConfig and not a PasswordEncoder in your UserService is the actual problem (or the problem in your design). You should inject a PasswordEncoder.
#Service
public class UserService {
private final SecurityService securityService;
private final IUserRepository userRepository;
private final PasswordEncoder encoder;
public UserService(SecurityService securityService, IUserRepository userRepository, PasswordEncoder encoder) {
this.securityService=securityService;
this.userRepository=userRepository;
this.encoder=encoder;
}
public User updateProfile (UserProfileDTO userProfileDTO) {
User user = userRepository.findByEmail(securityService.getLoggedUser());
user.setFirstName(userProfileDTO.getFirstName());
user.setLastName(userProfileDTO.getLastName());
user.setEmail(securityService.getLoggedUser());
if(!userProfileDTO.getConfirmPassword().equals(userProfileDTO.getPassword())){
throw new PasswordException("Password confirmation not match");
}
user.setPassword(encoder.encode(userProfileDTO.getPassword()));
return userRepository.save(user);
}
}
Now you can modify your test as well.
#ExtendWith(MockitoExtension.class)
public class Test {
#Mock
SecurityService securityService;
#Mock
IUserRepository userRepository;
#Mock
PasswordEncoder encoder;
#InjectMocks
UserService userService;
#Test
public void updateProfileTest() {
UserProfileDTO userDTO = new UserProfileDTO();
userDTO.setEmail("john#simons");
userDTO.setFirstName("John");
userDTO.setLastName("Simons");
userDTO.setPassword("pass");
userDTO.setConfirmPassword("pass");
User userForUpdate = new User();
userForUpdate.setFirstName("Joo");
userForUpdate.setLastName("Sim");
userForUpdate.setBalance(242.20);
userForUpdate.setEmail("john#simons");
userForUpdate.setPassword("pass");
userForUpdate.setRole("ROLE_USER");
User userUpdated = new User();
userUpdated.setFirstName("John");
userUpdated.setLastName("Simons");
userUpdated.setBalance(242.20);
userUpdated.setEmail("john#simons");
userUpdated.setPassword("pass");
userUpdated.setRole("ROLE_USER");
when(userRepository.findByEmail(any())).thenReturn(userForUpdate);
when(encoder.encode(any())).thenReturn(userUpdated.getPassword());
when(userRepository.save(any())).thenReturn(userUpdated);
User test = userService.updateProfile(userDTO);
assertEquals("john#simons",test.getEmail());
}
}
Now your service just depends on the classes it needs instead of knowing something about the configuration.

How to inject value to a bean in spring test?

i have a question here, please give some ideas.
I have two beans. FaceComparisonServerImpl depends on FaceServer.
When i want to test. I want to change the String in my 'FaceServer' bean.
#Service
public class FaceComparisonServerImpl implements FaceComparisonServer {
#Autowired
private FaceServer faceServer;
#Override
public FaceComparsionInfo getServerInfo() {
String serverInfo = faceServer.getServerInfo();
...
}
}
#Component
public class FaceServer {
#Autowired
private RestTemplate restTemplate;
//Not final, just to test.
private String version = "1.0";
private static final String CODE = "code";
private static final String MESSAGE = "message";
//Final
private static final String SERVER_URL = "http://127.0.0.1:8066/api/ZKComparison";
}
Bellow is my test code.
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = TestConfig.class)
public class FaceServerTestByTyler {
#Autowired
private FaceComparisonServer faceComparisonServer;
#Test
public void getServerInfo(){
//How can i modify the value of SERVER_URL in faceServer?
FaceComparsionInfo serverInfo = faceComparisonServer.getServerInfo();
System.out.println(serverInfo);
}
}
My question is:
How can i modified the value of 'version' and 'SERVER_URL' in #Bean(faceServer)?
Thanks you!
You need create FaceServer mock bean for test configuration.
And override required methods
#Configuration
Class TestConfig{
#Bean
#Primary
public FaceServer faceServer() {
return new FaceServer() {
#override
public String getServerInfo(){
return "required info";
}
};
}
}
The easiest way to customize the values is to make them Spring properties:
#Component
public class FaceServer {
#Value("${faceServer.version}")
private String version;
#Value("${faceServer.url}")
private String serverUrl;
// ...
}
You can either have default values for the #Value annotations or use some default property values in application.yml.
Now just override those properties in your test with the values you want:
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = TestConfig.class)
#TestPropertySource(properties = {
"faceServer.version=1.0",
"faceServer.url=http://127.0.0.1:8066/api/ZKComparison"
})
public class FaceServerTestByTyler {
#Autowired
private FaceComparisonServer faceComparisonServer;
// ...
}
However...
The second option is to make your classes more unit-testable. Prefer construction injection over field injection, and you can test your classes more independently.
#Service
public class FaceComparisonServerImpl implements FaceComparisonServer {
private final FaceServer faceServer;
public FaceComparisonServerImpl(FaceServer faceServer) {
this.faceServer = faceServer;
}
#Override
public FaceComparsionInfo getServerInfo() {
String serverInfo = faceServer.getServerInfo();
// ...
}
}
This now becomes unit-testable:
public class FaceServerTestByTyler {
private FaceComparisonServer faceComparisonServer;
private FaceServer faceServer;
#BeforeEach
public setup() {
faceServer = mock(FaceServer.class);
faceComparisonServer = new FaceComparisonServer(faceServer);
}
#Test
public void getServerInfo() {
when(faceServer.getServerInfo()).thenReturn(xxx);
// ...
}
}
The second option ends up with a test that runs much faster than any solutions that suggest to create a mock bean through a test configuration.

How to inject a mock object to a class when testing?

My user class is as follows,
public class UserResource {
#Inject UserService userService;
public boolean createUser(User user) {
DbResponse res = userService.addUser(user);
if(res.isSuccess){
return true;
}else{
return false;
}
}
}
My test class looks as follows,
public class UserResourceTest {
UserResource userResource;
#BeforeMethod
void beforeMethod() {
userResource = new UserResource();
}
#Test
public void test() {
User user= mock(User.class);
boolean res= userResource.createUser(user);
assert(res);
}
}
As you can see a UserService object should be injected into the UserResource class. How can I inject a mock UserService object to userResource object inside my test?
FYI:
This is part of a Jersey JAX-RS project.
I'm using Java CDI, mockito and testNG (as the test library).
Consider using explicit dependency principal via constructor injection as it states very clearly what is required by the class in order to perform its particular function.
public class UserResource {
private UserService userService;
#Inject
public UserResource(UserService userService) {
this.userService = userService;
}
public boolean createUser(User user) {
DbResponse res = userService.addUser(user);
if(res.isSuccess){
return true;
}else{
return false;
}
}
}
and mock the UserService as well and assign it to the subject under test. Configure the desired/mocked behavior for the test.
public class UserResourceTest {
#Test
public void test() {
//Arrange
boolean expected = true;
DbResponse mockResponse = mock(DbResponse.class);
when(mockResponse.isSuccess).thenReturn(expected);
User user = mock(User.class);
UserService mockService = mock(UserService.class);
when(mockService.addUser(user)).thenReturn(mockResponse);
UserResource userResource = new UserResource(mockService);
//Act
boolean actual = userResource.createUser(user);
//Assert
assert(expected == actual);
}
}
Although I completely support the answer of #Nkosi I'd like to add this for completeness:
Use Mockitos JUnitRule to reate the mocks as described here: http://www.vogella.com/tutorials/Mockito/article.html :
public class UserResourceTest {
#Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
#Mock
private DbResponse mockResponse;
#Mock
private UserService mockService;
#Test
public void test() {
//Arrange
boolean expected = true;
when(mockResponse.isSuccess).thenReturn(expected);
when(mockService.addUser(user)).thenReturn(mockResponse);
// ...
Also then you could also use Mockitos #InjectMocks annotation like this:
public class UserResourceTest {
#Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
#Mock
private DbResponse mockResponse;
#Mock
private UserService mockService;
#InjectMocks
private UserResource userResource; // do not instantiate in test method
// ...
But I personally would discourage from it.
Yes, it is more convenient since it determines by reflection which dependency injection method you use. But if you don't have a "seam" to inject a certain dependency (neither Costructor parameter, non final property nor setter of matching type) you don't get a compile error which I personally find problematic.

Full validation test in Spring Boot, injection failing

Hello everyone I wanted to tested the full validation of a Request in my Spring Boot application I mean no testing one validator at a time but all of them on the target object)
First I have my object :
public class UserCreationRequest {
#JsonProperty("profileId")
#NotNull
#ValidProfile
private Integer profileId;
}
Then my Validator (#ValidProfile):
#Component
public class ProfileValidator implements ConstraintValidator<ValidProfile, Integer> {
#Autowired
private IProfileService profileService;
#Autowired
private IUserRestService userRestService;
#Override
public void initialize(ValidProfile constraintAnnotation) {
}
#Override
public boolean isValid(Integer value, ConstraintValidatorContext context) {
if (value == null) {
return true;
}
RestUser restUser = userRestService.getRestUser();
ProfileEntity profileEntity = profileService.getProfile(value, restUser.getAccountId());
return profileEntity != null;
}
}
Now I write my unit test :
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = {ValidationTestConfiguration.class})
public class UserCreationRequestValidationTest {
private static LocalValidatorFactoryBean localValidatorFactory;
#Autowired
private IUserService userService;
#Autowired
private IProfileService profileService;
#Autowired
private IUserRestService restService;
#BeforeClass
public static void createValidator() {
localValidatorFactory = new LocalValidatorFactoryBean();
localValidatorFactory.setProviderClass(HibernateValidator.class);
localValidatorFactory.afterPropertiesSet();
}
#AfterClass
public static void close() {
localValidatorFactory.close();
}
#Test
public void validateUserCreationRequestStringfields() {
UserCreationRequest userCreationRequest = new UserCreationRequest();
/* Here fill test object*/
when(userService.getUser(any(Integer.class), any(Integer.class))).thenReturn(new UserEntity());
when(profileService.getProfile(any(Integer.class), any(Integer.class))).thenReturn(new ProfileEntity());
when(restService.getRestUser()).thenReturn(new RestUser());
Set<ConstraintViolation<UserCreationRequest>> violations
= localValidatorFactory.validate(userCreationRequest);
assertEquals(violations.size(), 8);
}
}
and my TestConfiguration is like that :
#Configuration
public class ValidationTestConfiguration {
#Bean
#Primary
public IProfileService profileService() {
return Mockito.mock(IProfileService.class);
}
#Bean
#Primary
public IUserRestService userRestService() { return Mockito.mock(IUserRestService.class); }
}
On execution I can see that in the test itself the injection works :
restService is mapped to "Mock for IUserRestService"
But in my validator it is not injected, userRestService is null.
Same thing for ProfileService
I tried several things seen here, nothing works (code is running, only test conf is failing)
This is because you do not produce the Validator bean so it can be injected.
As you manually instantiate the LocalValidatorFactoryBean, it cannot access to the spring DI defined for this test.
You should produce instead a bean for the Validator, or even reference an existing spring configuration to do so.

Using autowired dependencies with certain mock dependency in Spring4

I have a rest resource for signup and login. both in a controller class. the controller class has a dependency to a service class with the business logic. the service class has further dependencies. cause i use an embedded db for testing, i want to use the real dependencies of my app instead to mock them with something like #injectmock #mock. there is only one certain dependency i have to mock. its the dependency for sending emails after a signup process. how to write test cases with #autowired function and one certain mock dependency for email notification?
#Controller
public class AccountCommandsController {
#Autowired
private LogoutService service;
#RequestMapping(value = "/rest/login", method = RequestMethod.POST)
public ResponseEntity login(#RequestBody Account account) {
AccountLoginEvent accountLoginEvent = service.loginAccount(new RequestAccountLoginEvent(account.getEmailAddress(), account.getPassword()));
if (accountLoginEvent.isLoginGranted()) {
return new ResponseEntity(HttpStatus.ACCEPTED);
} else {
return new ResponseEntity(HttpStatus.UNAUTHORIZED);
}
}
#RequestMapping(value = "/rest/signup", method = RequestMethod.POST)
public ResponseEntity signup(#RequestBody Account account) {
AccountSignupEvent signedupEvent = service.signupAccount(new RequestAccountSignupEvent(account.getEmailAddress(), account.getPassword()));
if (signedupEvent.isSignupSuccess()) {
return new ResponseEntity(HttpStatus.ACCEPTED);
} else if (signedupEvent.isDuplicateEmailAddress()) {
return new ResponseEntity(HttpStatus.CONFLICT);
} else if (signedupEvent.isNoSignupMailSent()) {
return new ResponseEntity(HttpStatus.SERVICE_UNAVAILABLE);
} else {
return new ResponseEntity(HttpStatus.FORBIDDEN);
}
}
}
#Service
public class LogoutService {
#Autowired
private AccountsRepository accountsRepository;
#Autowired
private MailService mailService;
#Autowired
private HashService hashService;
public AccountSignupEvent signupAccount(RequestAccountSignupEvent signupEvent) {
if (accountsRepository.existEmailAddress(signupEvent.getEmailAddress())) {
return AccountSignupEvent.duplicateEmailAddress();
}
Account newAccount = new Account();
newAccount.setCreated(new Date());
newAccount.setModified(new Date());
newAccount.setEmailAddress(signupEvent.getEmailAddress());
newAccount.setPassword(signupEvent.getPassword());
newAccount.setVerificationHash(hashService.getUniqueVerificationHash());
SignupMailEvent mailSentEvent = mailService.sendSignupMail(new RequestSignupMailEvent(newAccount));
if (!mailSentEvent.isMailSent()) {
return AccountSignupEvent.noMailSent();
}
Account persistedAccount = accountsRepository.persist(newAccount);
return AccountSignupEvent.accountCreated(persistedAccount);
}
public AccountLoginEvent loginAccount(RequestAccountLoginEvent loginEvent) {
if (accountsRepository.existLogin(loginEvent.getEmailAddress(), loginEvent.getPassword())) {
return AccountLoginEvent.granted();
}
return AccountLoginEvent.denied();
}
}
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = TestConfiguration.class)
#Transactional
#TransactionConfiguration(defaultRollback = true)
public class LogoutTest {
private MockMvc mockMvc;
#Autowired
private AccountCommandsController controller;
#Before
public void setup() {
mockMvc = standaloneSetup(controller).build();
}
#Test
public void signupNoMail() throws Exception {
doReturn(AccountSignupEvent.noMailSent()).when(service).signupAccount(any(RequestAccountSignupEvent.class));
// when(controller.service.signupAccount(any(RequestAccountSignupEvent.class))).thenReturn(AccountSignupEvent.noMailSent());
mockMvc.perform(post("/rest/signup")
.content(new Gson().toJson(new Account(UUID.randomUUID().toString(), UUID.randomUUID().toString())))
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isServiceUnavailable());
}
}
I hope you see the problem. Every dependency works fine instead mailservice. I dont want to use #injectmock and #mock with MockitoAnnotations.initMocks(this); in my test file, because of the neccessary to provide for all dependencies mocks.
if your dependencies are running and you have a configuration class where you have defined the endpoint, you can use ConfigurableApplicationContext class, something like this:
public class test {
private static ConfigurableApplicationContext appContext;
private LogoutService service;
#AfterClass
public static void destroy() {
appContext.close();
}
#Before
public void setup() {
appContext = new AnnotationConfigApplicationContext(YourClassConfig.class);
service = appContext.getBean(LogoutService.class);
}
#Test
public void beansAreCreated() {
assertNotNull(service);
}
}
Or you can re-write your endpoint with a configuration class and you can use WireMock (http://wiremock.org) to emulate your dependency with real data, this should be something like this:
public class test {
#Rule
public WireMockRule wireMockRule = new WireMockRule(15000);
private static ConfigurableApplicationContext appContext;
private LogoutService service;
private static String serviceMockUrl;
#AfterClass
public static void destroy() {
appContext.close();
}
#Before
public void setup() {
serviceMockUrl = "http://localhost:" + wireMockRule.port();
appContext = new AnnotationConfigApplicationContext(TestConfig.class);
stubFor(get(urlEqualTo("urlToRequest")).
willReturn(aResponse().
withStatus(SC_OK).
withBody(createJsonArray("MapWithYourData").
withHeader("Content-Type", "application/json")));
service = appContext.getBean(LogoutService.class);
}
#Test
public void beansAreCreated() {
assertNotNull(service);
}
#Configuration
static class TestConfig {
#Bean
public PropertyPlaceholderConfigurer propertyPlaceholderConfigurer() {
return new PropertyPlaceholderConfigurer() {{
setProperties(new Properties() {{
setProperty("service.url", serviceMockUrl);
}});
}};
}
}
}
I hope this help you.
What you are trying to do is easily implemented using Spring Profiles.
On way to achieve it is the following:
#Configuration
public class TestConfiguration {
//this is the real mail service
#Bean
public MailService mailService() {
return new MailService(); //or whatever other bean creation logic you are using
}
//whatever else
}
#Configuration
#Profile("mockMail")
public class MockMailServiceConfig {
#Bean
#Primary
public MailService mockMailService() {
return mock(MailService.class);
}
}
Your test class would then look like:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = TestConfiguration.class)
#Transactional
#TransactionConfiguration(defaultRollback = true)
#ActiveProfiles("mockMail")
public class LogoutTest {
//do your testing
}
Note the use of #Primary in MockMailServiceConfig. I opted for this way since it wouldn't require you to introduce profiles anywhere else if you are not already using them. #Primary tells spring to use that specific bean if multiple candidates are available (in this case there is the real mail service and the mock service)

Categories

Resources