How to Unit test Spring-Boot Application main() method to get Jacoco test coverage - spring-boot

How to Unit test Spring-Boot Application main() method with SpringApplication.run() . I am wondering if it is possible to get Jacoco test coverage on this class. (Otherwise I will exclude it)
This question is similar, but not the same, as this question: Spring Boot, test main application class
I am using mockito-core 3.8 and mockito-inline.
This test code works for me but Jacoco does not pick it up as test coverage:
#SpringBootTest
#ActiveProfiles("test")
public class AutowireTest {
private static final String ARG = "";
private static final String[] ARGS = new String[]{ARG};
#Autowired
ConfigurableApplicationContext context;
#Test
public void main() {
try (MockedStatic<Application> appStatic = Mockito.mockStatic(Application.class);
MockedStatic<SpringApplication> springStatic = Mockito.mockStatic(
SpringApplication.class)) {
appStatic.when(() -> Application.main(ARGS))
.thenCallRealMethod();
springStatic.when(() -> SpringApplication.run(Application.class, ARGS))
.thenReturn(context);
// when
Application.main(ARGS);
//then
appStatic.verify(times(1),
() -> Application.main(ARGS));
springStatic.verify(times(1),
() -> SpringApplication.run(Application.class, ARGS));
}
}
}
Is Jacoco not able to show coverage on static methods?

Related

Arquillian test not failing

When dependency injection in Arquillian test class fails, maven still claims that all tests are run and are passed. This is major issue if we have hundreds of tests and some tests show as Green in Jenkins, but in reality they are not driven at all.
Is there a way to make the above test fail in Jenkins/Maven? One can use any Interface long as there is no implementation added to deployment.
#ExtendWith(ArquillianExtension.class)
class FailingArquillianTestIssueIT {
#Inject
DummyInterface dummyInterface;
#Deployment(testable = true)
public static JavaArchive create() throws Exception {
JavaArchive archive = ShrinkWrap.create(JavaArchive.class).addAsManifestResource(EmptyAsset.INSTANCE,
"beans.xml");
return archive;
}
#Test
void test1() {
assertTrue(false);
}
}

How to call a TESTNG class from a Springboot based selenium project

Running Testng class from Springboot application gives an error
I have a Springboot based Selenium Testng project.
When I do a Maven configuration like mvn clean package -Dtests= testng is file name of xml file, it works seemlessly.
Now I have a scenario where I need to get the testsuite name which user likes to test on commandline and use that and run the test suite.
I have the following in the #SpringBootApplication main method. Assuming I get the test suite thru commandline, I have this code, but the springboot servers keeps running in infinite without running the tests.
How could I fix it.
#SpringBootApplication
public class MyAutomationApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(MyAutomationApplication.class, args);
}
public void run(String... args) throws Exception {
System.out.println("Welcome!!");
//assuming i get the InitialLoginTest from commandline, i am passing the CLASS NAME to classes.add(new XmlClass("InitialLoginTest"));
TestNG tng = new TestNG();
XmlSuite suite = new XmlSuite();
suite.setName("Appium Test suite");
XmlTest test = new XmlTest(suite);
test.setName("Sample Test");
List<XmlClass> classes = new ArrayList();
classes.add(new XmlClass("InitialLoginTest"));
test.setXmlClasses(classes);
List<XmlSuite> suites = new ArrayList();
suites.add(suite);
tng.setXmlSuites(suites);
tng.run();
}
}
#SpringBootTest
public class InitialLoginTest {
#Test
void loading() {
System.out.println("In InitialLoginTest!!");
}
}

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.

SpringBoot Junit testing main method

I have below test for my spring boot main method.
The test tries to start the application 2 times which is expected.
First time when it starts the application it uses the Mock object hewever 2nd time it starts the application it calls the actual bean.
I have ReferenceDataService having #PostConstract method call which makes rest call to some other application which I don't want in my tests.
Another thing is that MqConfiguration which tries to connect to IBM queues that also I would like to avoid in my test.
Please note even though I have added #ComponentScan(excludeFilters... in my test class it does not exclude it.
How do I write test for my main method in this case?
#ActiveProfiles(profiles = {"test"})
#RunWith(SpringRunner.class)
#SpringBootTest(classes = MainApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT, properties = {
"camel.springboot.java-routes-include-pattern=**/NONE*"})
#EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, SecurityAutoConfiguration.class})
#DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
#ComponentScan(excludeFilters = {#ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = {MqConfiguration.class, ReferenceDataCache.class})})
public class MainApplicationTest {
#MockBean
private MqService mqService;
#MockBean
private ReferenceDataService referenceDataService;
#SpyBean
private ReferenceDataCache cacheSpy;
#Test
public void test() {
Mockito.when(referenceDataService.getCurrencies()).thenReturn(new HashMap<>());
Mockito.when(referenceDataService.getFrequencies()).thenReturn(null);
Mockito.when(referenceDataService.getDayCountTypes()).thenReturn(null);
Mockito.when(referenceDataService.getBusinessDayConverntions()).thenReturn(null);
Mockito.when(referenceDataService.getRateDefinations()).thenReturn(null);
Mockito.when(referenceDataService.getBusinessCalendar()).thenReturn(null);
Mockito.when(referenceDataService.getFinancingTypes()).thenReturn(null);
Mockito.when(referenceDataService.getStaffs()).thenReturn(null);
MainApplication.main(new String[]{});
}
}
MainApplication.java (The class to be tested)
#SpringBootApplication
#EnableJms
#EnableCaching
#AutoConfigureBefore(JmsAutoConfiguration.class)
public class MainApplication {
private static final Logger logger = LoggerFactory.getLogger(MainApplication.class);
public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}
}
One could split it into two separate testing parts as we should strive to test a single functionality per test (Single Responsibility Principle). You could model your testing like below:
#Test
public void applicationContextLoadedTest(){
}
#Test
public void applicationStartTest() {
//you can add your mocks as per your required dependencies and requirements
MainApplication.main(new String[] {});
}
Alternatively, if you are allowed to use PowerMockito, then the following link gives you a working example for verifying static invocations.PowerMockito - SpringBoot test

JUnit Test cases failing while running using Maven but works with Eclipse

I have a Junit test case which doesn't work if I run using Maven. But the same test case works when I run using Eclipse.
My Junit class is like this.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:/test-config.xml"} )
public class TestDaoImpl {
private final static Logger logger = Logger.getLogger(TestDaoImpl.class);
#Autowired
private MyDaoImpl myDao;
#Test
public void testMyDao() throws Exception {
logger.info("Called testMyDao()================");
// here myDao is null and throwing NullPointerException in sunfire log.
// But this works when I run using Eclipse.
List<MyObj> objList = myDao.getList();
}
#Test
public void testMyCode() throws Exception {
logger.info("Called testMyCode()================");
// this test case works with Maven
List<MyObj> objList = MyClass.getList();
}
}
The sunfire plugin was missing. When added it started working.

Resources