How to use dependency-injection with SpringBootTest - java

I have an application that uses SpringBoot for dependency injection and the app works fine, but testing fails because #Autowired fields aren't being injected during tests.
#SpringBootApplication
public class ProcessorInterface {
protected final static Logger logger = Logger.getLogger( ProcessorInterface.class );
public static void main(String[] args) {
try {
SpringApplication.run(ProcessorInterfaceRunner.class, args);
} catch (Exception ex) {
logger.error("Error running ProcessorInterface", ex);
}
}
}
#Component
#Configuration
#ComponentScan
public class ProcessorInterfaceRunner implements CommandLineRunner {
protected final static Logger logger = Logger.getLogger( ProcessorInterface.class );
#Autowired
private RequestService requestService = null;
#Autowired
private ValidatorService validatorService = null;
#Override
public void run(String... args) throws Exception {
ESPOutTransaction outTransaction = null;
outTransaction = new ESPOutTransaction();
// initialize outTransaction fields
...
// done initializing outTransaction fields
if (validatorService.isValid(outTransaction)) {
System.out.println(requestService.getRequest(outTransaction));
} else {
System.out.println("Bad Data");
}
}
}
#Service
public class ESPRequestService implements RequestService<ESPOutTransaction> {
#Autowired
ValidatorService validatorService = null;
#Override
public String getRequest(ESPOutTransaction outTransaction) throws IllegalArgumentException {
if (!validatorService.isValid(outTransaction)) {
throw new IllegalArgumentException("Invalid parameters in transaction object. " + outTransaction.toString());
}
StringBuffer buff = new StringBuffer("create request XML");
buff.append("more XML");
return buff.toString();
}
}
#Service
public class ESPValidatorService implements ValidatorService {
private static org.apache.log4j.Logger logger = Logger.getLogger(ESPValidatorService.class);
// declare some constants for rules
private static final int MAX_LENGTH_XYZ = 3;
#Override
public boolean isValid(OutTransaction outTransaction) {
ESPOutTransaction espOutTransaction = (ESPOutTransaction)outTransaction;
boolean isValid = true;
if (espOutTransaction == null) {
logger.warn("espOutTransaction is NULL");
isValid = false;
} else {
// XYZ is required
if (espOutTransaction.getXYZ() == null) {
logger.warn("XYZis NULL\r\n" + espOutTransaction.toString());
isValid = false;
}
// XYZ max length = MAX_LENGTH_XYZ
if (espOutTransaction.getXYZ() != null && espOutTransaction.getPubCode().trim().length() > MAX_LENGTH_XYZ) {
logger.warn("XYZis too long (max length " + MAX_LENGTH_XYZ + ")\r\n" + espOutTransaction.toString());
isValid = false;
}
}
return isValid;
}
}
These all work and I get good output when I run the app. When I try to test it though, it fails because it can't find ESPValidatorService to inject into ESPRequestService
#RunWith(Suite.class)
#SuiteClasses({ ESPOutTransactionValidatorTest.class, ESPRequestTest.class })
public class AllTests {}
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {ESPRequestService.class})
public class ESPRequestTest {
#Test
public void testGetRequest() {
ESPRequestService requestService = new ESPRequestService();
String XYZ = "XYZ";
ESPOutTransaction outTransaction = null;
outTransaction = new ESPOutTransaction();
outTransaction.setXYZ(XYZ);
String strRequest = "some expected request XML";
String request = requestService.getRequest(outTransaction);
assertEquals(request, strRequest);
}
}
#RunWith(SpringRunner.class)
#SpringBootTest(classes = ESPValidatorService.class)
public class ESPOutTransactionValidatorTest {
#Test
public void testIsValid() {
ESPValidatorService validatorService = new ESPValidatorService();
ESPOutTransaction outTransaction = null;
// test request = null
assertFalse(validatorService.isValid(outTransaction));
String XYZ = "XYZ";
outTransaction = new ESPOutTransaction();
outTransaction.setXYZ(XYZ);
// test all good
assertTrue(validatorService.isValid(outTransaction));
// test XYZ
outTransaction.setXYZ(null);
assertFalse(validatorService.isValid(outTransaction));
outTransaction.setXYZ("ABCD"); // too long
assertFalse(validatorService.isValid(outTransaction));
outTransaction.setXYZ(XYZ);
}
}
How can I get the unit tests to auto wire?

I see two problems :
1) you don't rely on Spring beans but you create instances with the new operator.
Instead of writing :
ESPRequestService requestService = new ESPRequestService();
you should let Spring inject the instance :
#Bean
ESPRequestService requestService;
2) The #SpringBootTest configuration is not correct.
In each test, you specified a very specific bean class in the classes attribute of #SpringBootTest :
#SpringBootTest(classes = ESPValidatorService.class)
public class ESPOutTransactionValidatorTest {
and
#SpringBootTest(classes = {ESPRequestService.class})
public class ESPRequestTest {
But classes attributes of #SpringBootTest serves to specify the annotated classes to use for loading an ApplicationContext.
The annotated classes to use for loading an ApplicationContext. Can
also be specified using #ContextConfiguration(classes=...). If no
explicit classes are defined the test will look for nested
#Configuration classes, before falling back to a
SpringBootConfiguration search.
So all configuration classes and beans of your application may not be discovered and loaded in the Spring container .
To be able to load all application beans during your tests, the most simple way is not specifying the classes attribute in the #SpringBootTest annotation :
#SpringBootTest
public class ESPRequestTest { ...}
It will look for a Spring bean that holds the #SpringBootConfiguration.
Ideally, it will found the #SpringBootApplication bean of your application.
If the package of the test class is located inside the package (or at a lower level) of the #SpringBootApplication class, it should be automatically discovered.
Otherwise the other way is specifying a configuration that will allow to load all required beans :
#SpringBootTest(classes = MySpringBootApplication.class)
public class ESPRequestTest { ...}

Related

Mock class with static method to execute test case in Springboot

Hi I have a class with static method as below
#Log4j2
#Profile("!ut")
#Component('CALC')
#ConditionalOnProperty(name = 'CALC', havingValue = 'VAL')
public class
ClassA extends ClassMain {
public static org.apache.logging.log4j.Logger narrLogger;
#Autowired
IHCRefDataMgr ihcRefDataMgr;
public ClassA(IHCRefDataMgr ihcRefDataMgr) {
super(ihcRefDataMgr);
this.ihcRefDataMgr = ihcRefDataMgr;
}
public boolean calculate(msg) {
narrLogger = Narratives.getNarrativeLogger(msg)
}
}
I have another class where i trace the logs
#Data
#Component
#ConditionalOnProperty(name = 'CALC', havingValue = 'VAL')
#Log4j2
public class ClassB {
Boolean prepareMap() {
Boolean status = true;
try {
Set<String> securityKeys = ConcurrentHashMap.newKeySet();
ClassA.narrLogger.trace("Security Keys for given BA: {}", securityKeys);
// doing some processing
} catch (Exception e) {
status = false;
System.out.println(e);
}
}
}
Now I want to write a test case for ClassB, In my debugger when I come to ClassA.narrLogger, i get null pointer exception. How can i mock ClassA and allow it to pass assuming i dont want to test narrLogger.
Test Case
#Log4j2
#SpringBootTest
#TestPropertySource(properties = {"spring.profiles.active=test,ut", "calculator.name = ClassA", "eureka.client.enabled = false"})
public class ClassBTest {
ClassB classb;
#Test
public void prepareMapTest() {
var status = classb.prepareMap();
Assertions.assertEquals(true, status)
}
}
While running test case, it falls in exception as null pointer comes at ClassA.narrLogger

Spring programmatic bean autowired as proxy instead of target

I created an annotation for creating ThreadPoolTaskExecutors populated with values from the environment. However, when I autowire the bean it gives me a proxy and calling the methods on the proxy gives the wrong values.
If I manually access the target class, then I get the correct values.
Executor exec = (Executor) ((Advised) executor).getTargetSource().getTarget();
ThreadPoolTaskExecutor taskExec = (ThreadPoolTaskExecutor) exec;
I have been scratching my head for a while now as to why I'm getting a proxy bean, but can't seem to figure it out.
I am using an annotation to import my registrar class that implements ImportBeanDefinitionRegistrar to register the bean. The registrar code is below:
public class ExecutorEnumerationRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware {
public static final String CORE_POOL_SIZE = "corePoolSize";
public static final String MAX_POOL_SIZE = "maxPoolSize";
public static final String QUEUE_CAPACITY = "queueCapacity";
public static final String THREAD_NAME_PREFIX = "threadNamePrefix";
private static final String REJECTED_EXECUTION_HANDLER = "rejectedExecutionHandler";
private static final String NAMES = "names";
private static final String REJECTED_HANDLER = "rejectedHandler";
private Environment env;
#Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
Map<String, Object> attrs = importingClassMetadata.getAnnotationAttributes(ThreadPoolTaskExecutorCreator.class.getName(), true);
final String[] beanNames = (String[]) attrs.get(NAMES);
final String[] policyClass = (String[]) attrs.get(REJECTED_HANDLER);
for (int x = 0; x < beanNames.length; x++) {
createAndRegisterBean(beanNames[x], policyClass[x], registry);
}
}
private void createAndRegisterBean(String name, String policyClass, BeanDefinitionRegistry registry) {
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setBeanClass(ThreadPoolTaskExecutor.class);
bd.setAutowireCandidate(true);
bd.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
MutablePropertyValues mpv = bd.getPropertyValues();
populateProperties(mpv, name, policyClass);
registry.registerBeanDefinition(name, bd);
}
private void populateProperties(MutablePropertyValues mpv, String name, String policyClass) {
mpv.add(CORE_POOL_SIZE, Integer.valueOf(env.getProperty(name + "." + CORE_POOL_SIZE)));
mpv.add(MAX_POOL_SIZE, Integer.valueOf(env.getProperty(name + "." + MAX_POOL_SIZE)));
mpv.add(QUEUE_CAPACITY, Integer.valueOf(env.getProperty(name + "." + QUEUE_CAPACITY)));
try {
mpv.add(REJECTED_EXECUTION_HANDLER, Class.forName(policyClass).newInstance());
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
e.printStackTrace();
}
mpv.add(THREAD_NAME_PREFIX, name + "-");
}
#Override
public void setEnvironment(Environment environment) {
env = environment;
}
}
Annotation to import the registrar:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
#Documented
#Import(ExecutorEnumerationRegistrar.class)
public #interface ThreadPoolTaskExecutorCreator{
String[] names();
String[] rejectedHandler() default ThreadPoolPolicyHandlers.CALLER_RUNS_POLICY;
}
I have tested with the following code:
Spring Boot Class:
#EnableDiscoveryClient
#ComponentScan("my.test.classes")
#ThreadPoolTaskExecutorCreator(names = {"testExecutor"}, rejectedHandler = ThreadPoolPolicyHandlers.DISCARD_POLICY)
#SpringBootApplication(exclude = {DataSourceAutoConfiguration.class,
SessionAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
JpaRepositoriesAutoConfiguration.class,
JndiDataSourceAutoConfiguration.class,
JndiConnectionFactoryAutoConfiguration.class,
RedisAutoConfiguration.class, RedisRepositoriesAutoConfiguration.class})
public class TestBoot {
public static void main(String[] args) {
SpringApplication.run(TestBoot.class, args);
}
}
All versions from spring-boot-starter-parent 1.4.5.RELEASE
I wrote a JUnit test that checks the values and it passes. The only time it doesn't work is when I autowire it in a Spring Boot eureka application. Is there anything I can do so that it doesn't autowire a proxy bean? I have searched through the documentation and looked at all the related classes, but I don't see anything related to why it's a proxy. Also, why does it give incorrect values when accessed through the proxy?
Seems you are missing the code for registering the instance of your ImportBeanDefinitionRegistrar ( in your example that is ExecutorEnumerationRegistrar )
So there are two ways to register the ImportBeanDefinitionRegistrar use the #Import annotation directly or implement the ImportSelector interface which can give you more generic configuration options.
For your case simply adding the #Import({ExecutorEnumerationRegistrar.class}) on the Configuration class will do the trick.
#EnableDiscoveryClient
#ComponentScan("my.test.classes")
#ThreadPoolTaskExecutorCreator(names = {"testExecutor"}, rejectedHandler = ThreadPoolPolicyHandlers.DISCARD_POLICY)
// THIS IS REQUIRED
#Import({ExecutorEnumerationRegistrar.class})
// See Above
#SpringBootApplication(exclude = {DataSourceAutoConfiguration.class,
SessionAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
JpaRepositoriesAutoConfiguration.class,
JndiDataSourceAutoConfiguration.class,
JndiConnectionFactoryAutoConfiguration.class,
RedisAutoConfiguration.class, RedisRepositoriesAutoConfiguration.class})
public class TestBoot {
public static void main(String[] args) {
SpringApplication.run(TestBoot.class, args);
}
}
and just remember to use the #Qualifier when autowiring the instance of ThreadPoolTaskExecutor. See example component
#Component
public class Component {
#Autowired
#Qualifier("testExecutor")
private ThreadPoolTaskExecutor exec;
// you methods
}

Spring Autowired field null on Test Helper Class

Structure..
src/test/java
config
TestConfiguration.java
hooks
WebDriverHooks.java
nicebank
RunSteps.java
OtherSteps..
support
ATMUserInterface.java
KnowsTheDomain.java
#Autowired is correctly injecting KnowsTheDomain when placed Steps in nicebank package. But I am unable to #Autowired KnowsTheDomain when placed in Helper classes such as WebDriverHooks and ATMUserInterface
Does it require configuring annotation when autowiring to different packages? I am running Cucumber runner..
From WebDriverHook.java and ATMUserInterface.java, the field private KnowsTheDomain helper; is returning null instead of singleton instance. I need them to return what it returns when I run Steps in nicebank package.
Anyone has idea why this helper field is null?
TestConfiguration.java
#Configuration
#ComponentScan(basePackages = { "support"})
public class TestConfiguration {
#Bean
public static KnowsTheDomain knowsTheDomain() {
return new KnowsTheDomain();
}
}
WebDriverHooks.java
#ContextConfiguration(classes = TestConfiguration.class, loader=AnnotationConfigContextLoader.class)
#Configurable(autowire = Autowire.BY_TYPE)
public class WebDriverHooks {
#Autowired
private KnowsTheDomain helper;
#After
public void finish(Scenario scenario) {
try {
byte[] screenshot =
helper.getWebDriver().getScreenshotAs(OutputType.BYTES);
scenario.embed(screenshot, "image/png");
} catch (WebDriverException somePlatformsDontSupportScreenshots) {
System.err.println(somePlatformsDontSupportScreenshots.getMessage());
}
finally {
helper.getWebDriver().close();
}
}
}
RunSteps.java - this runs the Cucumber runner..
#RunWith(Cucumber.class)
#CucumberOptions(
plugin = {"pretty", "html:out"},
snippets = SnippetType.CAMELCASE,
features = "classpath:cucumber",
dryRun = false)
#ContextConfiguration(classes = TestConfiguration.class)
public class RunSteps {
}
KnowsTheDomain.java
#Component
public class KnowsTheDomain {
private Account myAccount;
private CashSlot cashSlot;
private Teller teller;
private EventFiringWebDriver webDriver;
public Account getMyAccount() {
if (myAccount == null) {
myAccount = new Account();
}
return myAccount;
}
public CashSlot getCashSlot() {
if (cashSlot == null) {
cashSlot = new CashSlot();
}
return cashSlot;
}
public Teller getTeller() {
if (teller == null) {
teller = new ATMUserInterface();
}
return teller;
}
public EventFiringWebDriver getWebDriver() {
if (webDriver == null) {
System.setProperty("webdriver.chrome.driver", "src/test/resources/chromedriver_win32/chromedriver.exe");
webDriver = new EventFiringWebDriver(new ChromeDriver());
}
return webDriver;
}
}
ATMUserInterface.java
#ContextConfiguration(classes = TestConfiguration.class, loader=AnnotationConfigContextLoader.class)
#Configurable(autowire = Autowire.BY_TYPE)
public class ATMUserInterface implements Teller {
#Autowired
private KnowsTheDomain helper;
#Override
public void withdrawFrom(Account account, int dollars) {
try {
helper.getWebDriver().get("http://localhost:" + ServerHooks.PORT);
helper.getWebDriver().findElement(By.id("Amount"))
.sendKeys(String.valueOf(dollars));
helper.getWebDriver().findElement(By.id("Withdraw")).click();
} catch (Exception e) {
System.err.println("err" + e);
}
}
}
#Autowired will work only in beans.
So make sure where are you using #Autowired annotation.
Add hooks package to #ComponentScan as below
#ComponentScan(basePackages = { "support", "hooks" })

Spring 4.07 Junit Test and Autowired

Hi I'm using Spring and CDI.
In my unit test I want to test a Class that uses the #Autowired annotation.
Problem is if I create a instance of this class and call a method all annotated objects are null.
In basic the annotation works. Just whithin my unit test it doesn't
This is my Unit Test. In here Autowired works. In my test I create an instance of the DemoConsumerBean.class and call the method requestJobsFromPublishedJobsApi in here I have also some Autowired declaration. Problem is all instances are null!
#RunWith(SpringJUnit4ClassRunner.class)
#ActiveProfiles("development")
#TestExecutionListeners({ DependencyInjectionTestExecutionListener.class, FirstbirdTestExecutionListener.class, FlywayTestExecutionListener.class })
#ContextConfiguration(locations = { "classpath:hibernate-spring.xml" })
#FlywayTest
public class DemoConsumerBeanTest extends AbstractJUnit4SpringContextTests {
#Autowired
private CustomerManager customerManager;
#Autowired
private DemoDetailsManager demoDetailsManager;
#Before
public void setup() {
CamelContext context = new DefaultCamelContext();
exchange = new DefaultExchange(context);
}
#Test
public void requestJobsFromPublishedJobsApiTest() throws NoSuchDataException {
DemoConsumerBean demoConsumerBean = new DemoConsumerBean();
customer = new Customer();
customer.setCustomerId(15);
customer = customerManager.getCustomerById(customer);
// This one works
DemoDetails demoDetails = demoDetailsManager.getDemoDetailsByCustomerId(customer);
demoConsumerBean.requestJobsFromPublishedJobsApi(exchange, customer);
PublishedJobs apiJobs = exchange.getIn().getBody(PublishedJobs.class);
assertNotNull(apiJobs);
}
}
public class DemoConsumerBean {
#Autowired
protected CustomerManager customerManager;
#Autowired
protected DemoDetailsManager demoDetailsManager;
#Autowired
protected MessageLogManager messageLogManager;
public void requestJobsFromPublishedJobsApi(Exchange exchange, Customer customer) throws NoSuchDataException {
//this one is null!
DemoDetails demoDetails = demoDetailsManager.getDemoDetailsByCustomerId(customer);
PublishedJobs jobs = null;
if (demoDetails == null || StringUtils.isBlank(demoDetails.getDemoApiUrl())) {
throw new NoSuchDataException("No demo data found for customer " + customer.getCustomerFirstbirdId());
}
....
}
}
Using new in new DemoConsumerBean(); bypasses spring, that's your issue.
Either use a DemoConsumerBean instance from spring (i.e. autowired in the test) or add setters and use them to "manually autowire" in DemoConsumerBean in your test:
#Test
public void requestJobsFromPublishedJobsApiTest() throws NoSuchDataException {
DemoConsumerBean demoConsumerBean = new DemoConsumerBean();
demoConsumerBean.setCustomerManager(this.customerManager)
// etc
Some reading: Spring framework reference - The IoC container

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