I'm trying to build a simple test of a simple component marked with websocket scope. The problem is that I get this error:
Scope 'websocket' is not active for the current thread;
Which makes sense, because I'm using a simulated WebSocket client to perform a login, and on the client side context of the Spring app the websocket session created by the client has no impact.
What is the proper way to test websocket scoped components?
Component class:
#Service
#Scope(scopeName = "websocket", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class TrackerService {
private final ConcurrentMap<String, Collection<Geolocation>> vehicleBeingTracked = new ConcurrentHashMap<>();
public void startTracking(String plateSequence) {
vehiclesBeingTracked.put(plateSequence, new ArrayList<>());
}
public void stopTracking(String plateSequence) {
vehiclesBeingTracked.remove(plateSequence);
}
public void spotVehicle(String plateSequence, Geolocation geo) {
vehiclesBeingTracked.get(plateSequence).add(geo);
}
public boolean isBeingTracked(String plateSequence) {
return vehiclesBeingTracked.containsKey(plateSequence);
}
}
Controller class:
#Controller
#MessageMapping("/operational/tracker")
public class TrackerController {
#Autowired
private TrackerService trackerService;
#MessageMapping("/plate/{plateSequence}/track.start")
public void startTracking(#DestinationVariable("plateSequence") String plateSequence) {
trackerService.startTracking(plateSequence);
}
}
Test class:
#RunWith(SpringRunner.class)
#ContextConfiguration
#SpringBootTest(classes = UnifyApplication.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
#ActiveProfiles("test")
public class TrackerTest {
#Autowired
private TrackerService trackerService;
#Test
public void startTracking() {
TrackerClient client = new TrackerClient("ws://localhost:9050/operational/websocket", "admin", "admin");
client.connectAndWait();
client.send("/operational/tracker/plate/ABC1234/track.start");
TimeUnit.SECONDS.sleep(1);
boolean result = trackerService.isBeingTracked("ABC1234"); // Here is the error
Assert.assertTrue(result);
}
}
Try to spy the trackerService service with the following code inside test class:
#SpyBean
private TrackerService trackerService;
#Test
public void startTracking() {
TrackerClient client = new
TrackerClient("ws://localhost:9050/operational/websocket", "admin", "admin");
client.connectAndWait();
client.send("/operational/tracker/plate/ABC1234/track.start");
TimeUnit.SECONDS.sleep(1);
boolean result = Mockito.verify(trackerService).isBeingTracked("ABC1234");
Assert.assertTrue(result);
}
Updated answer:
#MockBean
private TrackerService trackerService;
#Test
public void startTracking() {
Mockito.doAnswer((Answer<Object>) invocationOnMock -> {
Object[] args = invocationOnMock.getArguments();
assertEquals("ABC1234", invocationOnMock.getArgument(0));
return null;
}).when(sessionTracker).sessionDestroyed(Mockito.any());
TrackerClient client = new
TrackerClient("ws://localhost:9050/operational/websocket", "admin", "admin");
client.connectAndWait();
client.send("/operational/tracker/plate/ABC1234/track.start");
TimeUnit.SECONDS.sleep(1);
}
Related
Test container configuration
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
#Testcontainers
public abstract class TestContainerFixture {
#Container
protected static final GenericContainer mongoDBContainer;
protected static final Map<String, Object> properties;
static {
mongoDBContainer = new GenericContainer(DockerImageName.parse("mongo:4.0.10"))
.withExposedPorts(27017)
.withReuse(true);
mongoDBContainer.start();
properties = Map.of("mongodb.uri",
String.format("mongodb://%s:%s/FeteBird-Product",
mongoDBContainer.getContainerIpAddress(),
mongoDBContainer.getMappedPort(27017)));
}
protected static ApplicationContext applicationContext;
}
Application.yml
mongodb:
uri: "mongodb://${MONGO_HOST:localhost}:${MONGO_PORT:27017}/FeteBird-Product"
database: "FeteBird-Product"
JUnit Testing
#MicronautTest(rebuildContext = true)
public class SubCategoryCreateTest extends TestContainerFixture {
#BeforeAll
public static void initUnitTest() {
applicationContext = ApplicationContext.run(properties, ConstantValues.TEST_ENVIRONMENT);
}
#Test
#DisplayName("Should create sub category with valid claim as Owner")
void shouldCreateSubCategoryWithValidClaimAsOwner() {
// Given
HttpResponse<CategoryModel> categoryrsp = this.httpRequestToCreateCategory();
assertEquals(categoryrsp.getStatus(), HttpStatus.CREATED);
// When
SubCategoryModel subCategoryModel = new SubCategoryModel(null, "Men swim sweat", "Men swim seat description");
HttpRequest request = HttpRequest.POST(String.format("%s/%s/%s", "category", categoryrsp.body().id(), "/sub-category"), subCategoryModel)
.bearerAuth(bearerAccessRefreshToken.getAccessToken());
HttpResponse<SubCategoryModel> rsp = client.toBlocking().exchange(request, SubCategoryModel.class);
var item = rsp.body();
// Then
assertEquals(rsp.getStatus(), HttpStatus.CREATED);
assertTrue(item.id() != null);
}
}
The configuration is not over-ridden in the service layer, Controller has the dependency on service layer
Update after implementing TestPropertyProvider works
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
#Testcontainers
public class TestContainerFixture implements TestPropertyProvider {
protected GenericContainer mongoDBContainer;
#Override
public Map<String, String> getProperties() {
mongoDBContainer = new GenericContainer(DockerImageName.parse("mongo:4.0.10"))
.withExposedPorts(27017)
.withReuse(true);
mongoDBContainer.start();
return Map.of("mongodb.uri",
String.format("mongodb://%s:%s/FeteBird-Product",
mongoDBContainer.getContainerIpAddress(),
mongoDBContainer.getMappedPort(27017)));
}
}
#MicronautTest
public class SubCategoryCreateTest extends TestPropertyProvider {
#Test
#DisplayName("Should create sub category with valid claim as Owner")
void shouldCreateSubCategoryWithValidClaimAsOwner() {
// Given
HttpResponse<CategoryModel> categoryrsp = this.httpRequestToCreateCategory();
assertEquals(categoryrsp.getStatus(), HttpStatus.CREATED);
// When
SubCategoryModel subCategoryModel = new SubCategoryModel(null, "Men swim sweat", "Men swim seat description");
HttpRequest request = HttpRequest.POST(String.format("%s/%s/%s", "category", categoryrsp.body().id(), "/sub-category"), subCategoryModel)
.bearerAuth(bearerAccessRefreshToken.getAccessToken());
HttpResponse<SubCategoryModel> rsp = client.toBlocking().exchange(request, SubCategoryModel.class);
var item = rsp.body();
// Then
assertEquals(rsp.getStatus(), HttpStatus.CREATED);
assertTrue(item.id() != null);
}
}
You need to implement TestPropertyProperty and set up your database URL in the getProperties method that it requires
See the guide here for an example
I want to perform the Integration test for which I want to create a test DB and add some data.
how should I point to the test DB while doing an integration test?
Thanks for Help......
You can use testcontainers for achieving this. You can watch this video to get an idea about this and how to configure it in your spring boot application
For your spring integration test create a configuration like as shown below
AbstractIT.java
#Testcontainers
#SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT, properties = {"spring.main.allow-bean-definition-overriding=true"})
#AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) // don't replace our DB with an in-memory one
#ContextConfiguration(initializers = AbstractIT.DockerPostgresDataSourceInitializer.class)
#TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public abstract class AbstractIT {
private static PostgreSQLContainer<?> postgresDBContainer = new PostgreSQLContainer<>("postgres:9.6")
.withUrlParam("TC_DAEMON", "true")
.withFileSystemBind("docker/db", "/docker-entrypoint-initdb.d", BindMode.READ_WRITE);
static {
postgresDBContainer.start();
}
public static class DockerPostgresDataSourceInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
#Override
public void initialize(ConfigurableApplicationContext applicationContext) {
Assertions.assertNotNull(applicationContext);
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(
applicationContext,
"spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true",
"spring.datasource.driver-class-name="+postgresDBContainer.getDriverClassName(),
"spring.datasource.url=" + postgresDBContainer.getJdbcUrl(),
"spring.datasource.username=" + postgresDBContainer.getUsername(),
"spring.datasource.password=" + postgresDBContainer.getPassword()
);
}
}
}
Now you can write your Integration test like as shown in the below sample example
UserControllerIT.java
class UserControllerIT extends AbstractIT {
#Autowired
private TestRestTemplate template;
#Autowired
private UserRepository userRepository;
#Test
#Order(1)
#DisplayName("Testing to get all the user details")
void getAllUsersTest() {
ResponseEntity<List<UserDTO>> response = this.template.exchange("/v1/users", GET, HttpEntity.EMPTY, new ParameterizedTypeReference<List<UserDTO>>() {
});
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(response.getBody())
.isNotEmpty()
.hasSize(3)
.extracting(UserDTO::getEmail).containsAnyOf("user1#some.com");
}
#Test
#Order(2)
#DisplayName("Testing for saving user details")
void saveUsersTest() {
ResponseEntity<Void> response = this.template.postForEntity("/v1/users", new HttpEntity<>(buildUserRequest()), Void.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED);
long usersCount = userRepository.count();
assertThat(usersCount).isEqualTo(4);
}
#Test
#Order(3)
#DisplayName("Testing to deleting user details by id")
void deleteUsersTest() {
this.template.delete("/v1/users/{id}", singleParam("id", "21"));
boolean userExists = userRepository.existsById(21L);
assertThat(userExists).isFalse();
}
#Test
#Order(4)
#DisplayName("Testing to finding user details by id")
void findUserByIdTest() {
ResponseEntity<UserDTO> response = this.template.getForEntity("/v1/users/{id}", UserDTO.class, singleParam("id", "22"));
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(response.getBody())
.extracting(UserDTO::getEmail, UserDTO::getFirstName, UserDTO::getLastName)
.containsExactly("user2#some.com", "John", "Duke");
}
private UserDTO buildUserRequest() {
return UserDTO.builder()
.email("user4#some.com")
.lastName("Maria")
.firstName("Fernandes")
.build();
}
private Map<String, String> singleParam(String key, String value) {
Map<String, String> params = new HashMap<>();
params.put(key, value);
return params;
}
}
You can see the full running application under this Github Repo - https://github.com/nidhishkrishnan/stackoverflow/tree/master/employee-testcontainer
I'm trying to test my controller method in Play framework 2.4.6.
Inside my controller method, I have the following code:
User user = accountService.getUserByEmail(email);
if (user == null) {
//Path A
}
//Path B
When running the test, user will be null. Hence I can't test Path B. I tried returning a User using Mockito when, but it didn't work either. Is there any other way of doing it?
Below is my test code:
RequestBuilder request = new RequestBuilder()
.method("POST")
.bodyForm(ImmutableMap.of("email", "test#test.com"))
.uri(controllers.routes.ResetPasswordController.postResetPassword().url());
when(accountService.getUserByEmail(anyString())).thenReturn(new User());
assertEquals(OK, route(request).status());
Thanks to #Andriy for pointing me in the right direction for Dependency Injection.
I managed to solved the issue with the following setup.
Test:
public class TestClass {
#Inject
Application application;
final AccountService accountServiceMock = mock(AccountService.class);
#Before
public void setup() {
Module testModule = new AbstractModule() {
#Override
public void configure() {
bind(AccountService.class).toInstance(accountServiceMock);
}
};
GuiceApplicationBuilder builder = new GuiceApplicationLoader()
.builder(new ApplicationLoader.Context(Environment.simple()))
.overrides(testModule);
Guice.createInjector(builder.applicationModule()).injectMembers(this);
Helpers.start(application);
}
#Test
public void testMethod() throws Exception {
RequestBuilder request = new RequestBuilder()
.session("userId", "1")
.uri(controllers.routes.AccountController.addAccount().url());
running(application, () -> {
when(accountServiceMock.addAccount().thenReturn(true);
assertEquals(OK, route(request).status());
});
}
Controller:
#Singleton
public class AccountController extends Controller {
private AccountService accountService;
#Inject
public Controller(AccountService a) {
accountService = a;
}
public Result addAccount() {
boolean success = accountService.addAccount();
}
}
Interface:
#ImplementedBy(AccountServiceImpl.class)
public interface AccountService {
boolean addAccount();
}
Implementation:
public class AccountServiceImpl implements AccountService {
#Override
public boolean addAccount() {
}
}
My knowledge is minimal on the concepts going on here, but roughly:
Controller is stateless just like HTML, hence you need runtime dependency injection to get Play to recognise the mock object.
Useful documentations:
https://www.playframework.com/documentation/2.4.x/JavaTestingWithGuice
https://www.playframework.com/documentation/2.4.x/JavaDependencyInjection
Code:
RabbitMQListener:
#Component
public class ServerThroughRabbitMQ implements ServerThroughAMQPBroker {
private static final AtomicLong ID_COUNTER=new AtomicLong();
private final long instanceId=ID_COUNTER.incrementAndGet();
#Autowired
public ServerThroughRabbitMQ( UserService userService,LoginService loginService....){
....
}
#Override
#RabbitListener(queues = "#{registerQueue.name}")
public String registerUserAndLogin(String json) {
.....
}
ServerConfig:
#Configuration
public class ServerConfig {
#Value("${amqp.broker.exchange-name}")
private String exchangeName;
#Value("${amqp.broker.host}")
private String ampqBrokerHost;
#Value("${amqp.broker.quidco.queue.postfix}")
private String quidcoQueuePostfix;
#Value("${amqp.broker.quidco.queue.durability:true}")
private boolean quidcoQueueDurability;
#Value("${amqp.broker.quidco.queue.autodelete:false}")
private boolean quidcoQueueAutodelete;
private String registerAndLoginQuequName;
#PostConstruct
public void init() {
registerAndLoginQuequName = REGISTER_AND_LOGIN_ROUTING_KEY + quidcoQueuePostfix;
public String getRegisterAndLoginQueueName() {
return registerAndLoginQuequName;
}
public String getLoginAndCheckBonusQueueName() {
return loginAndCheckBonusQuequName;
}
#Bean
public ConnectionFactory connectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory(ampqBrokerHost);
return connectionFactory;
}
#Bean
public AmqpAdmin amqpAdmin() {
return new RabbitAdmin(connectionFactory());
}
#Bean
public TopicExchange topic() {
return new TopicExchange(exchangeName);
}
#Bean(name = "registerQueue")
public Queue registerQueue() {
return new Queue(registerAndLoginQuequName, quidcoQueueDurability, false, quidcoQueueAutodelete);
}
#Bean
public Binding bindingRegisterAndLogin() {
return BindingBuilder.bind(registerQueue()).to(topic()).with(REGISTER_AND_LOGIN_ROUTING_KEY);
}
}
TestConfig:
#EnableRabbit
#TestPropertySource("classpath:test.properties")
public class ServerThroughAMQPBrokerRabbitMQIntegrationTestConfig {
private final ExecutorService=Executors.newCachedThreadPool();
private LoginService loginServiceMock=mock(LoginService.class);
private UserService userServiceMock =mock(UserService.class);
#Bean
public ExecutorService executor() {
return executorService;
}
#Bean
public LoginService getLoginServiceMock() {
return loginServiceMock;
}
#Bean
public UserService getUserService() {
return userServiceMock;
}
#Bean
#Autowired
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
factory.setMaxConcurrentConsumers(5);
return factory;
}
#Bean
#Autowired
public RabbitTemplate getRabbitTemplate(ConnectionFactory connectionFactory) {
final RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
return rabbitTemplate;
}
#Bean
public ServerThroughRabbitMQ getServerThroughRabbitMQ() {
return new ServerThroughRabbitMQ(userServiceMock, loginServiceMock,...);
}
}
Integration tests:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes ={ServerConfig.class,ServerThroughAMQPBrokerRabbitMQIntegrationTestConfig.class})
#Category({IntegrationTest.class})
#TestPropertySource("classpath:test.properties")
public class ServerThroughAMQPBrokerRabbitMQIntegrationTest {
final private ObjectMapper jackson = new ObjectMapper();
#Autowired
private ExecutorService executor;
#Autowired
private ServerThroughRabbitMQ serverThroughRabbitMQ;
#Autowired
private RabbitTemplate template;
#Autowired
private TopicExchange exchange;
#Autowired
UserService userService;
#Autowired
LoginService loginService;
#Autowired
private AmqpAdmin amqpAdmin;
#Autowired
private ServerConfig serverConfig;
final String username = "username";
final String email = "email#email.com";
final Integer tcVersion=1;
final int quidcoUserId = 1;
final String jwt = ProcessLauncherForJwtPhpBuilderUnitWithCxtTest.EXPECTED_JWT;
#Before
public void cleanAfterOthersForMyself() {
cleanTestQueues();
}
#After
public void cleanAfterMyselfForOthers() {
cleanTestQueues();
}
private void cleanTestQueues() {
amqpAdmin.purgeQueue(serverConfig.getRegisterAndLoginQueueName(), false);
}
#Test
#Category({SlowTest.class,IntegrationTest.class})
public void testRegistrationAndLogin() throws TimeoutException {
final Waiter waiter = new Waiter();
when(userService.register(anyString(), anyString(), anyString())).thenReturn(...);
when(loginService....()).thenReturn(...);
executor.submit(() -> {
final RegistrationRequest request = new RegistrationRequest(username, email,tcVersion);
final String response;
try {
//#todo: converter to convert RegistrationRequest inside next method to json
response = (String) template.convertSendAndReceive(exchange.getName(), REGISTER_AND_LOGIN_ROUTING_KEY.toString(), jackson.writeValueAsString(request));
waiter.assertThat(response, not(isEmptyString()));
final RegistrationResponse registrationResponse = jackson.readValue(response, RegistrationResponse.class);
waiter.assertThat(...);
waiter.assertThat(...);
} catch (Exception e) {
throw new RuntimeException(e);
}
waiter.resume();
});
waiter.await(5, TimeUnit.SECONDS);
}
}
When I run that test separetly , everything works fine, but when I run it with other tests the mocked ServerThroughRabbitMQ isn't being used, so some spring caches force to use old rabbit listener.
I tried to debug it and I can see, that correct bean is being autowired to the test, but for some reason old listener is using(old bean field instanceId=1 new mocked bean instanceId=3) and test failing(Not sure how it's possible, so if in case of existing old bean I assume to get an autowire exception).
I tried to use #DirtiesContext BEFORE_CLASS, but faced anoter problem(see here)
RabbitMQ and Integration Testing can be hard, since Rabbit MQ keeps some kind of state:
- messages from previous tests in queues
- listeners from previous tests still listening on queues
There are several approaches:
Purge all queues before you start the test (that might be what you mean by cleanTestQueues())
Delete all queues (or use temporary queues) and recreate them before each test
Using the Rabbit Admin Rest API killing listeners or connections of previous tests
delete the vhost and recreating the infrasture for each test (which is the most brutal way)
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)