Why is my Spring application run from my spring boot unit test - spring

I have a basic spring data application and I have written a unit test. What appears to happen is that when I run the Spring test my application run method gets called as well. I would like to know why this is and how to stop it please.
I have tried using active profiles but that doesnt fix the problem
#SpringBootApplication
#EntityScan({ "com.demo" })
public class Application implements ApplicationRunner {
#Autowired
private IncrementalLoadRepository repo;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Override
public void run(ApplicationArguments args) throws Exception {
IncrementalLoad incrementalLoad = new IncrementalLoad("fred", Instant.now(), Instant.now(), Instant.now());
repo.save(incrementalLoad);
}
and the unit test........
#RunWith(SpringRunner.class)
#SpringBootTest(classes = { Application.class })
#ActiveProfiles("test")
public class IncrementalLoadServiceTest {
#Autowired
private IncrementalLoadService incrementalLoadService;
#Test
public void checkInitialRecords_incrementalLoad() {
List<IncrementalLoad> incrementalLoads = incrementalLoadService.list();
assertEquals(3, incrementalLoads.size());
}

So I think I found the solution. I created another #SpringBootApplication class in my test folders. Initially that failed but I believe thats because the entity scan annotation pointed to packages where my "production" #SpringBootApplication was. I moved that class up a level and it all seems to work ok now.

Related

Is there a way to use Spring boot beans in a Gatling simulation?

I am currently writing a Spring boot application that will perform loadtests on another app. I want to use Gatling to manage the tests, but I need it to access the configuration that I defined in beans of my Spring app.
Here is what I would like to see working :
public class MySimulation extends Simulation {
#Autowired
private JMSConnectionFactoryBeanClass myConnectionFactory;
public MySimulation() {
JmsProtocolBuilder jmsProtocol = jms.connectionFactory(myBean);
ScenarioBuilder scn = scenario("My Simulation Scenario")
.exec(
jms("test")
.send()
.queue("myQueue")
.textMessage("message")
);
{
setUp(
scn.injectOpen(rampUsers(10).during(5))
).protocols(jmsProtocol);
}
}
When I hardcode the configuration into the simulation class and remove all #Autowired thing, everything works, so it must be comming from the dependency injection. Does anybody know if there is a way to us spring beans in a gatling simulation ?
Following Stéphane Landelle advice, here is what I came up with, but instead of creating my app context inside of the simulation, I figured out how to run the simulation along with my spring app using gatling API :
public class GatlingRunner {
public static void run() {
GatlingPropertiesBuilder props = new GatlingPropertiesBuilder();
props.simulationClass("path.to.Simulation");
Gatling.fromMap(props.build());
}
}
This is how I modified my spring app :
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
GatlingRunner.run();
}
}
Finally, to use spring beans in the simulation, I wrote a context provider that would make the link between spring and gatling :
#Component
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext context;
public static ApplicationContext getApplicationContext() {
return context;
}
#Override
public void setApplicationContext(ApplicationContext context)
throws BeansException {
ApplicationContextProvider.context = context;
}
}
Now, to get a bean inside of the simulation, all I needed was this :
Bean myBean = ApplicationContextProvider.getApplicationContext()
.getBean("myBean", Bean.class)
You can't use #Autowired. You have to create an ApplicationContext programmatically and pull the JMSConnectionFactoryBeanClass from it.
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = MySimulation.class, loader = SpringApplicationContextLoader.class)
public class MySimulation extends GatlingTest {
#Autowired
private JMSConnectionFactoryBeanClass myConnectionFactory;
#Test
public void test() {
...
}
}

Spring boot + cucumber in main scope. Can I autowire a step definition?

I believe this is a very particular case, but I am building some cucumber tests for some third-party applications we use.
Since I am not really testing my own application, I created a maven project and configured cucumber to run in the main folder (not the test folder).
This is my entrypoint class:
#SpringBootApplication
public class ExecutableMain implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(ExecutableMain.class, args);
}
#Override
public void run(String... args) {
// args logic...
JUnitCore.runClasses(MyCucumberTest.class);
}
}
And my test class:
#RunWith(Cucumber.class)
#CucumberOptions(
plugin = {"pretty", "html:target/cucumber", "json:target/cucumber/cucumber.json"},
glue = {"cucumber.app", "cucumber.steps"}
)
public class MyCucumberTest {
#AfterClass
public static void tearDown(){
// quit the browser
}
}
This currently works fine, but I want to add spring features to my tests.
Specifically, I want to autowire something in my cucumber steps.
Stepdefs:
public class MyStepdefs {
#Autowired
private ConfigProperties properties;
#Given("^Something")
public void example() {
//...
}
I searched around and found people saying I should add the ContextConfiguration annotation in the steps. I did it like so:
#ContextConfiguration(classes = ExecutableMain.class, loader = SpringBootContextLoader.class)
public class MyStepdefs {
But this resulted in a loop during start up.
Can I achieve what I need?
Ok, so I got it to work following https://stackoverflow.com/a/37586547/1031162
Basically I changed:
#ContextConfiguration(classes = ExecutableMain.class, loader = SpringBootContextLoader.class)
To:
#ContextConfiguration(classes = ExecutableMain.class, initializers = ConfigFileApplicationContextInitializer.class)
I am not 100% sure how/why it worked, but it did.

springboottest how to prevent running application

I have the standard Application class which runs a Spring batch ETL:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
with my Junit test doing something like:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
public class MyServiceTest {
#Autowired
MyService myService;
#Test
public void testInsertions() {
//do stuff with assertions
}
}
My problem is that when I execute the junit test, the application also kicks off the ETL then executes the test. How to prevent the application from running?
I think there are a lot of alternatives and it really depends on what you are trying to achieve.
One of the options would be to run your tests with a specific profile, like testing, and configure your ETLs (I'm assuming they are just jobs) to be configured based on some property or specific profile.
For example:
Testing class
#ActiveProfiles("testing")
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
public class MyServiceTest {
...
}
Job/ETL classes
#Component
#Profile("!testing")
public class JobEtlService {
}
Hope it helps.

spring-boot: Application loads but tests fail

I am experiencing rather strange thing when using Spring Boot. Lets get with it.
I have an app which, when ran from spring-boot:run, loads perfectly fine and I can use my server. However, if I try to run tests (either via launching test from IntelliJ or via surefire plugin) context fails to load.
Issue lies within this class (only relevant part shown):
#RestController
#RequestMapping(
value = "/sa/revisions/"
)
#SuppressWarnings("unchecked")
class RevisionController {
#Autowired
// cant autowire this field
private RepositoryEntityLinks repositoryEntityLinks = null;
/* omitted */
}
And here is my main class:
#EnableAsync
#EnableCaching
#EnableAutoConfiguration
#EnableConfigurationProperties
#Import({
SecurityConfiguration.class,
DataConfiguration.class,
RestConfiguration.class
})
public class SpringAtomApplication {
#Autowired
private DataLoaderManager dataLoaderManager = null;
public static void main(String[] args) {
SpringApplication.run(SpringAtomApplication.class, args);
}
#Bean
public CacheManager cacheManager() {
final GuavaCacheManager manager = new GuavaCacheManager();
manager.setAllowNullValues(false);
return manager;
}
#PostConstruct
private void doPostConstruct() {
this.dataLoaderManager.doLoad();
}
}
As I said, application loads without an issue when ran normally, however when it comes to this simple test, everything falls apart:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = SpringAtomApplication.class)
public class SpringAtomApplicationTests {
#Test
public void contextLoads() {
}
}
Would appreciate any suggestion, because I'd love to start with testing it.
You should set SpringApplicationContextLoader in your test class:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(
classes = SpringAtomApplication.class,
loader = SpringApplicationContextLoader.class)
public class SpringAtomApplicationTests {
#Test
public void contextLoads() {
}
}
With that you can test non-web features (like a repository or a service) or start an fully-configured embedded servlet container and run your tests using MockMvc.
Reference: http://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/test/SpringApplicationContextLoader.html

Run another project's web service before start tests

IntelliJ project has two modules: Spring Data Rest app and client. Both apps are Spring bootable apps. I made a lot of tests at client and now before every test iteration I have to run the rest service manually.
Test class looks like that:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {BusinessRepositoryImpl.class})
public class BusinessLogoRepositoryTest {
..
}
Here is the service:
#EnableAutoConfiguration
#ImportResource({
"classpath:spring/persistenceContext.xml"
})
#Import(DataServiceConfiguration.class)
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
So the question is if it's possible somehow to add the context of service to test class and run the service before test's start.
You can create a TestSuite with 2 methods annotated with #BeforeClass and #AfterClass to start the service before the tests and stop it after the tests are done.
Draft code to visualize :) what I mean is below.
#RunWith(SpringJUnit4ClassRunner.class)
#SuiteClasses({UnitTest1.class, UnitTest2.class, ... })
#EnableAutoConfiguration
#ImportResource({
"classpath:spring/persistenceContext.xml"
})
#Import(DataServiceConfiguration.class)
public class TestSuite {
#BeforeClass
public void start() throws Exception {
SpringApplication.run(Application.class, args);
}
#AfterClass
public void start() throws Exception {
SpringApplication.shutdown();
}
}

Resources