JUnit Application Suite Testing - java

I am trying to create a junit test suite that will run all of the test suites within the application... - this is what I have and as far as I can find it should work but it keeps telling me that no tests are found.
import static org.junit.Assert.*;
import org.junit.Test;
/**
* #author Jason
*
*/
#Test
public class applicationTest extends TestCase {
public applicationTestSuite(String name) {
super(name);
}
public static Test suite() {
TestSuite suite = new TestSuite("ApplicationTestSuite");
suite.addTest(domain.AllDomainTests.suite());
suite.addTest(services.AllServicesTests.suite());
suite.addTest(business.AllBusinessTests.suite());
return suite;
}
}
An example of one of the test suites it should be running -
package business;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
#RunWith(Suite.class)
#SuiteClasses({ ItemMgrTest.class })
public class AllBusinessTests {
}

You need to mark #Test annotation on test method
API Document
The Test annotation tells JUnit that the public void method to which it is attached can be run as a test case. To run the method, JUnit first constructs a fresh instance of the class then invokes the annotated method. Any exceptions thrown by the test will be reported by JUnit as a failure. If no exceptions are thrown, the test is assumed to have succeeded [...]

You can specify Suite classes in your #SuiteClasses, for instance:
#RunWith(Suite.class)
#SuiteClasses({ AllBusinessTests.class })
public class AllTests {
}
The suite() method is a JUnit 3 thing, and won't find any methods or tests in your suite, because you're using JUnit 4.

Related

Is there a TestNG annotation that start running before the class constructor just like JUnit #BeforeAll does?

The JUnit #BeforeAll tests are executed before the constructor and the declared class variables (as they should).
The TestNG #BeforeClass calls first the class constructor and classes variables before it runs itself.
Is there a TestNG annotation that starts to run BEFORE the class constructor is called,
just like JUnit #BeforeAll does?
I run a test with both TestNG #BeforeClass and JUnit #BeforeAll and they both give different responses.
JUnit example:
package Junit;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import pages.MyClass;
public class TestJunit {
#BeforeAll
public static void setUp(){
System.out.println("1 - #BeforeAll Junit");
}
private MyClass str = new MyClass();
public TestJunit() {
System.out.println("3 - Junit Class Constructor");
}
#Test
public void test1(){
System.out.println("4 - Starting Junit Tests");
}
}
TestJunit - Junit Response:
#BeforeAll Junit
My Custom Class Constructor
Junit Class Constructor
Starting Junit Tests
TestNG example:
package TestNG;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import pages.MyClass;
public class TestTestNG {
#BeforeClass(alwaysRun = true)
public void setUp(){
System.out.println("1 - BeforeAll TestNG");
}
private MyClass str = new MyClass();
public TestTestNG() {
System.out.println("3 - TestNG Class Constructor");
}
#Test
public void test1(){
System.out.println("4 - Starting TestNG Tests");
}
}
TestTestNG - TestNG Response:
My Custom Class Constructor
TestNG Class Constructor
BeforeAll TestNG
Starting TestNG Tests
My Custom Class:
package pages;
public class MyClass {
public MyClass() {
System.out.println("2 - My Custom Class Constructor");
}
}
I want a TestNG solution (because #BeforeClass is not working) that will give the same response as the JUnit (#BeforeAll) solution.
Is there a TestNG annotation that starts to run BEFORE the class constructor is called,
just like JUnit #BeforeAll does?
Yes there is. You can use the #BeforeTest or the top level #BeforeSuite annotations to use as a "BeforeAll" alternative. Both of the will run before the test class constructors.
Following is the TestNG annotation execution order so you get the idea.

How to test main class of Spring-boot application

I have a spring-boot application where my #SpringBootApplication starter class looks like a standard one. So I created many tests for all my functionalities and send the summary to sonarqube to see my coverage.
For my starter class Sonarqube tells me that I just have 60% coverage. So the average coverage is not good as expected.
My Test class is just the default one.
#RunWith(SpringRunner.class)
#SpringBootTest(classes = ElectronicGiftcardServiceApplication.class)
public class ElectronicGiftcardServiceApplicationTests {
#Test
public void contextLoads() {
}
}
So how can I test my main class in the starter class of my application?
All these answers seem overkill.
You don't add tests to make a metric tool happy.
Loading a Spring context of the application takes time. Don't add it in each developer build just to win about 0.1% of coverage in your application.
Here you don't cover only 1 statement from 1 public method. It represents nothing in terms of coverage in an application where thousands of statements are generally written.
First workaround : make your Spring Boot application class with no bean declared inside. If you have them, move them in a configuration class (for make them still cover by unit test). And then ignore your Spring Boot application class in the test coverage configuration.
Second workaround : if you really need to to cover the main() invocation (for organizational reasons for example), create a test for it but an integration test (executed by an continuous integration tool and not in each developer build) and document clearly the test class purpose :
import org.junit.Test;
// Test class added ONLY to cover main() invocation not covered by application tests.
public class MyApplicationIT {
#Test
public void main() {
MyApplication.main(new String[] {});
}
}
You can do something like this
#Test
public void applicationContextLoaded() {
}
#Test
public void applicationContextTest() {
mainApp.main(new String[] {});
}
I solved in a different way here. Since this method is there only as a bridge to Spring's run, I annotated the method with #lombok.Generated and now sonar ignores it when calculating the test coverage.
Other #Generated annotations, like javax.annotation.processing.Generated or javax.annotation.Generated might also work but I can't test now because my issue ticket was closed.
package com.stackoverflow;
import lombok.Generated;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class Application {
#Generated
public static void main(String... args) {
SpringApplication.run(Application.class, args);
}
}
I had the same goal (having a test that runs the main() method) and I noticed that simply adding a test method like #fg78nc said will in fact "start" the application twice : once by spring boot test framework, once via the explicit invocation of mainApp.main(new String[] {}), which I don't find elegant.
I ended up writing two test classes : one with #SpringBootTest annotation and the empty test method applicationContextLoaded(), another one without #SpringBootTest (only RunWith(SpringRunner.class)) that calls the main method.
SpringBootApplicationTest
package example;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.boot.test.context.SpringBootTest;
#RunWith(SpringRunner.class)
#SpringBootTest
public class SpringBootApplicationTest {
#Test
public void contextLoads() {
}
}
ApplicationStartTest
package example;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringRunner;
#RunWith(SpringRunner.class)
public class ApplicationStartTest {
#Test
public void applicationStarts() {
ExampleApplication.main(new String[] {});
}
}
Overall, the application is still started two times, but because there is now two test classes. Of course, with only these two tests methods, it seems overkill, but usually more tests will be added to the class SpringBootApplicationTest taking advantage of #SpringBootTest setup.
In addition to the answers above, here is a unit test of a SpringBoot application's main method for if you are using JUnit 5 and Mockito 3.4+:
try (MockedStatic<SpringApplication> mocked = mockStatic(SpringApplication.class)) {
mocked.when(() -> { SpringApplication.run(ElectronicGiftCardServiceApplication.class,
new String[] { "foo", "bar" }); })
.thenReturn(Mockito.mock(ConfigurableApplicationContext.class));
ElectronicGiftCardServiceApplication.main(new String[] { "foo", "bar" });
mocked.verify(() -> { SpringApplication.run(ElectronicGiftCardServiceApplication.class,
new String[] { "foo", "bar" }); });
}
It verifies that the static method run() on the SpringApplication class is called with the expected String array when we call ElectronicGiftCardServiceApplication.main().
Same idea as awgtek and Ramji Sridaran, but their solutions are for JUnit 4.
You can Mock SpringApplication since that is a dependency of the method under test. See how here.
I.e.
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.springframework.boot.SpringApplication;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
import static org.powermock.api.mockito.PowerMockito.verifyStatic;
#RunWith(PowerMockRunner.class)
public class ElectronicGiftcardServiceApplicationTest {
#Test
#PrepareForTest(SpringApplication.class)
public void main() {
mockStatic(SpringApplication.class);
ElectronicGiftcardServiceApplication.main(new String[]{"Hello", "World"});
verifyStatic(SpringApplication.class);
SpringApplication.run(ElectronicGiftcardServiceApplication.class, new String[]{"Hello", "World"});
}
}
Using junit
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.springframework.boot.SpringApplication;
import static org.assertj.core.api.Assertions.*;
class WebsiteApplicationTests {
#Test
void testApplication() {
MockedStatic<SpringApplication> utilities = Mockito.mockStatic(SpringApplication.class);
utilities.when((MockedStatic.Verification) SpringApplication.run(WebsiteApplication.class, new String[]{})).thenReturn(null);
WebsiteApplication.main(new String[]{});
assertThat(SpringApplication.run(WebsiteApplication.class, new String[]{})).isEqualTo(null);
}
}
Add these dependencies in pom.xml
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.8.0</version>
<scope>test</scope>
</dependency>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>your.awesome.package.Application</mainClass>
</configuration>
</plugin>
If you aim for 100% coverage, one thing you can do is simply not having a main method at all. You still require a class annotated with #SpringBootApplication but it can be empty.
Be warned though as it has its drawbacks and other tools that rely on main can break.
This simple mock test for SpringApplication does not invoke any methods but just tests the starter app. [uses PowerMockRunner.class]
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.springframework.boot.SpringApplication;
#RunWith(PowerMockRunner.class)
#PowerMockIgnore({"com.sun.org.apache.xerces.*", "javax.xml.*", "org.xml.*", "javax.management.*"})
public class JobsAppStarterTest {
#Test
#PrepareForTest(SpringApplication.class)
public void testSpringStartUp() {
PowerMockito.mockStatic(SpringApplication.class);
SpringApplication.run(JobsAppStarter.class, new String[] {"args"});
JobsAppStarter.main(new String[] {"args"});
}
}
If the idea is to exclude the SpringApplication class from sonar scan (which is the recommended way of doing it), you can exclude it with the following configuration in the build.gradle
plugins {
id 'org.sonarqube' version '3.4.0.2513'
}
sonarqube {
properties {
property "sonar.exclusions", "**/*Application.java"
}
}
Even though this question has been answered extensively I had a use case that is not covered here that is perhaps interesting to share. I am validating some properties at startup and I wanted to assert that the application would fail to start if these properties were configured wrong. In JUnit4 I could have done something like this:
#ActiveProfiles("incorrect")
#SpringBoot
public class NetworkProbeApplicationTest {
#Test(expected=ConfigurationPropertiesBindException.class)
public void contextShouldNotLoadWhenPropertiesIncorrect() {
}
}
But in JUnit5 you can no longer add the "expected" value to your #Test annotation and you have to do it differently. And since I wanted to start the application with an incorrect set of properties I needed to pass in which profile to use as a main() argument. I could not really find this documented anywhere, but passing in arguments through the main() method requires you to prefix your arguments with a double hyphen and separate the key and value with an equals sign. A complete test would look like this:
import org.junit.jupiter.api.Test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesBindException;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class NetworkProbeApplicationTest {
#Test
public void contextShouldNotLoadWhenPropertiesIncorrect() {
Exception exception = assertThrows(ConfigurationPropertiesBindException.class, () -> {
SpringApplication.run(NetworkProbeApplication.class, "--spring.profiles.active=incorrect");
});
String expectedMessage = "Error creating bean with name 'dnsConfiguration': Could not bind properties to 'DnsConfiguration' : prefix=dns";
assertTrue(exception.getMessage().contains(expectedMessage));
}
}

Junit - Executing a class with variety of tests that resides on different classes

I have the following test classes:
TestClass1 (10 tests)
TestClass2 (20 tests)
TestClass3 (15 tests)
TestClass4 (25 tests)
I would like to create a test class called
SmallTestClass
that executes 2 tests from TestClass1, 3 tests from TestClass2, 5 tests from TestClass3, 4 tests from TestClass4
How can a achieve this ? I Use spring framework and junit 4
You would need a combination of Junit 4 Category and Suite to achieve this. Note that the Category is still an experimental feature, having been introduced in v4.8.
The below example would only ensure only someTest1() gets run (I used v4.11 myself to test) since it's categorized to be a SanityTest.
The aggregator:
import org.junit.experimental.categories.Categories;
import org.junit.experimental.categories.Categories.IncludeCategory;
import org.junit.runner.RunWith;
import org.junit.runners.Suite.SuiteClasses;
#RunWith (Categories.class)
#SuiteClasses (SomeTest.class)
#IncludeCategory (SanityTests.class)
public class JunitSuiteTest {
}
The class containing the actual tests:
import org.junit.Test;
import org.junit.experimental.categories.Category;
public class SomeTest {
#Test
#Category (SanityTests.class)
public void someTest1()
{
System.out.println("test 1");
}
#Test
public void someTest2()
{
System.out.println("test 2");
}
}
A marker class to help categorize:
public class SanityTests {
}

How to run PowerMock on dynamically created TestCase

I was trying to mock my test suites. My test framework creates test cases by scanning test files on disk. So each time the test cases are dynamically created.
I was trying to use PowerMock. Below is the thing I tried first.
public class GroupTestcase_T extends TestSuite {
static void run() {
scan();
junit.textui.TestRunner.run(g);
}
static void scan() {
// scan disk
for (MyTestCase t : tests) { addTest(t); }
}
}
#RunWith(PowerMockRunner.class)
#PrepareForTest(ClassToStub.class)
public class MyTestCase extends TestCase {
public MyTestCase(TestInfo info) {...}
#Override
protected void setUp() throws Exception {
PowerMockito.mockStatic(ClassToStub.class);
when(ClassToStub.methodToStub())
.thenReturn(new FakeProxy());
}
#Test
public void test() throws Exception {
// Test!
}
}
Above code seems not working:
Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods.
Those methods cannot be stubbed/verified.
2. inside when() you don't call method on mock but on some other object.
3. the parent of the mocked class is not public.
It is a limitation of the mock engine.
I traced the code and found that PowerMockRunner are not called at all.
Also I tried manually force Junit to run it with PowerMockRunner:
Result result = junit.run(new PowerMockRunner(MyTestCase.class));
PowerMockRunner has only one constructor that takes the test class as parameter. My test cases are different each time but all share the same class.
Any idea how to use PowerMock if TestCase are dynamically created?
I was using Junit 4 / PowerMock 1.5
You can generate your tests with the parameterized tests feature and apply the #PowerMockRule.
import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import java.util.Collection;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.rule.PowerMockRule;
#RunWith(Parameterized.class)
#PrepareForTest(ClassToStub.class)
public class MyTestCase{
#Parameters
public static Collection<Object[]> scan() {
return Arrays.asList(new Object[][] {
{ new TestInfo() }, { new TestInfo() } });
}
#Rule
public PowerMockRule rule = new PowerMockRule();
public MyTestCase(TestInfo info) {
// ...
}
#Test
public void test() throws Exception {
PowerMockito.mockStatic(ClassToStub.class);
PowerMockito.when(ClassToStub.methodToStub()).thenReturn(new FakeProxy());
assertTrue(ClassToStub.methodToStub() instanceof FakeProxy);
}
}
Beware, in your example, you are mixing junit 3 (extends TestSuite, protected setUp) and junit 4 (#Test) test definitions.

Setting Test Suite to Ignore

I have many Test Suites with each one contains many Test Classes. Here is how they look like:
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
#RunWith(Suite.class)
#SuiteClasses( {ATest.class, BTest.class})
public class MyFirstTestSuite {
#BeforeClass
public static void beforeClass() throws Exception {
// load resources
}
#AfterClass
public static void afterClass() throws Exception {
// release resources
}
}
Sometimes I want to disable a whole Test Suite completely. I don't want to set each test class as #Ignore, since every test suite loads and releases resources using #BeforeClass and #AfterClass and I want to skip this loading/releasing when the test suite is ignored.
So the question is: is there anything similar to #Ignore that I can use on a whole Test Suite?
You can annotate the TestSuite with #Ignore.
#RunWith(Suite.class)
#SuiteClasses({Test1.class})
#Ignore
public class MySuite {
public MySuite() {
System.out.println("Hello world");
}
#BeforeClass
public static void hello() {
System.out.println("beforeClass");
}
}
doesn't produce any output.
SlowTest is a class defined by user. It can be empty (without any functions or attributes). You can name it whatever you want:

Categories