How to order Tests while building Spring Boot application - spring-boot

I am building spring boot application with unit testing. I have entities those are dependent on each other, Eg: I have User and Roles. To create User i should need Roles. I am testing roles and user object resources with MockMvc. I created Test class for Each Entity. When i run test UserTest class is executing Before Role Test class. So, all my tests are failing. I need help to run Test classes in an order.

As I mentioned in the comments, the best solution to such a problem is to avoid dependencies between test classes.
This can be achieved via proper test fixture setup and tear down (e.g., #Before and #After methods in JUnit 4).
Having said that, however, it is possible to order test classes in JUnit 4 if you execute them via a suite as in the following example.
#RunWith(Suite.class)
#SuiteClasses({RoleTests.class, UserTests.class})
public class MyTestSuite {
public static class RoleTests {
#Test
public void roleTest() {
System.err.println("roleTest");
}
}
public static class UserTests {
#Test
public void userTest() {
System.err.println("userTest");
}
}
}
That always prints:
roleTest
userTest

Related

JUnit 5 test suite choose test methods

Having some test classes with Junit 5 and Spring Boot REST controller testing.
#SpringBootTest
#AutoConfigureMockMvc
public class TestClassA {
#Autowired
private MockMvc mockMvc;
#Test
#WithMockUser
public void testMethod1() {
...
}
#Test
#WithMockUser
public void testMethod2() {
...
}
// more test methods
}
#SpringBootTest
#AutoConfigureMockMvc
public class TestClassB {
#Autowired
private MockMvc mockMvc;
#Test
#WithMockUser
public void testMethod1() {
...
}
// more test methods
#Test
#WithMockUser
public void testMethodX() {
// requires that TestClassA.testMethod2()
// must be run first
}
}
The test classes run, each testing a specific REST controller, but how to achieve a new test method TestClassB.testMethodX()?
I thought to create a test suite in JUnit 5 and specify which test methods to run, also in order:
1. run TestClassA.testMethod2()
2. run TestClassB.testMethodX()
I know about two annotations:
- #SelectPackages
- #SelectClasses
But selecting specific test methods not possible?
Is this achievable with JUnit 5?
I cannot answer both of your questions, but at least I can give you a hint on how to choose a set of test methods which should be run.
For my understanding unit/integration tests should not rely on a specific order to pass successfully. Is it really necessary, or can you realize important requirements for tasks using things like #Before annotations?
In my setup, I run Spring Boot with Gradle.
JUnit Tags & Filtering
JUnit 5 allows to add tag(s) to your test methods, using the #Tag annotation. With this feature it is possible to filter your test methods on test execution. Have a look at baeldung.com for a short tutorial.
Tag your test methods
Mark your test methods with a tag fitting to your purpose, like this.
#Test
#Tag("IntegrationTest")
public void testMethod1() {
...
}
// more test methods
#Test
#Tag("UnitTest")
public void testMethodX() {
...
}
Run tagged methods
Run tagged methods using IntelliJ
If you use the IntelliJ IDE, it is rather simple to run test methods with specific tags. See jetbrains.com docs or stackoverflow.
Run -> Edit Configurations... -> + (Add new configuration) -> JUnit
As Test kinds choose Tags
Insert your desired tag at Tag expression
Run tagged methods using Gradle
In case you want to run your test methods for instance in a continuous integration pipeline you probably run the tests using Gradle or Maven. For Gradle I can also show you a possibility to run methods with specific tags.
Open build.gradle
For dependencies you probably already have integrated the JUnit 5 framework, similar to this:
dependencies {
// [...]
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
// [...]
}
You also should have a test task.
test {
useJUnitPlatform()
}
The command $ gradlew test would now run all defined test methods. So, to run just a specific set of methods, I suggest to create custom tasks, like this.
test {
useJUnitPlatform()
}
task unitTests(type: Test) {
useJUnitPlatform {
includeTags 'UnitTest'
}
}
task integrationTests(type: Test) {
useJUnitPlatform {
includeTags 'IntegrationTest'
}
}
After that, you are able run the tasks on the command line interface, e.g.: $ gradlew unitTests and it would just run the tasks you defined in your custom task.

Run a JUnit Test with multiple Spring contexts in different projects

I have a generic code base that I need to test with different implementations and runtime configurations. Think services with multiple DAO implementations. I have generic unit tests which test the Dao interface (need the Dao autowired), and I want to invoke these from different projects.
Essentially I want something like this.
In the shared, generic project my tests will live.
So essentially, in shared project I have my tests, for example.
public class ApiTest {
#Autowired
DaoBase myDao;
#Test
public void testSomething(){
}
}
Then in the other project(s) that implement the Dao, I would have:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(classes = { ImplementationConfigA.class })
public class ImplemtationTesterA {
//somehow invoke ApiTest.class?
}
.
#Configuration
public class ImplementationConfigA{
#Bean
DaoBase daoBase {
return new DaoImplementationGraphDB();
}
}
Again, there are multiple projects that implement the DAO layer in different ways, and I want to share the generic tests.
If I could combine #RunWith(SpringJUnit4ClassRunner.class) and #RunWith(Suite.class), it would be exactly what I desire, but that doesn't seem possible. i.e. this would be effectively what I want, which is not possible:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(classes = { ImplementationConfigA.class })
#RunWith(Suite.class)
#Suite.SuiteClasses({ ApiTest.class })
public class ImplemtationTesterA {
...
There's got to be a trick to get something like this working.. Any ideas? Thanks!
Use profiles
#Configuration
#Profile("profileA")
public class ImplementationConfigA{
#Bean
DaoBase daoBase {
return new DaoImplementationGraphDB();
}
}
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(classes = { ImplementationConfigA.class })
#RunWith(Suite.class)
#Suite.SuiteClasses({ ApiTest.class })
#ActiveProfiles("profileA");
public class ImplemtationTesterA {
...
Just to update:
I ended placing all the shared tests is one project, and then in each DAO implementation project creating a "dummy" test class that extended each shared test class. Not as convenient as defining a suite since each test class had to be duplicated in each implementation project, but it works.
So in the original example, the only change necessary was to make ImplemtationTesterA extend ApiTest.

Running multiple tests using RestAssured serially

I have a Spring Boot application which is capable of running Integration tests using Rest Assured.
There is a single test class which has multiple test cases. I wish to run the test cases serially as given in the class.
public class ItemControllerTest{
#Before
public void setUp(){
...
}
#Test
public void test1(){
...
}
#Test
public void test2(){
...
}
}
When I run integration test,it seems test2 is getting executed before test1.
But I want them to run in the order they are written
I am not familiar with spring-boot, but if you are using Junit to run your tests, then you can run them serially by adding the following annotation above your class:
#FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class ItemControllerTest{
// tests will run in order here
}

SpringJUnit4ClassRunner with JUnit testsuite error

I am trying to setup Junit test suite with Spring for the first time and tried with couple of changes in my classes, but no luck and ended up with this error : "junit.framework.AssertionFailedError: No tests found in Myclass"
Briefly, I have 2 test classes both are from same base class which loads Spring context as below
#RunWith( SpringJUnit4ClassRunner.class )
#ContextConfiguration( locations =
{
"classpath:ApplicationContext.xml"
})
I tried adding those 2 test classes into a suite as below
#RunWith( SpringJUnit4ClassRunner.class )
#SuiteClasses({ OneTest.class, TwoTest.class })
public class MyTestSuite extends TestCase {
//nothing here
}
I am running this test suite from ant. But, this gives me an error saying "No tests found"
However, If I run the individual 2 test cases from ant, they work properly. Not sure why is this behaviour, I am sure missing something here. Please advice.
As mentioned in the comments, we run the TestSuite with #RunWith(Suite.class) and list all the test cases with #SuiteClasses({}). In order to not repeat the #RunWith(SpringJunit4ClassRunner.class) and #ContextConfiguration(locations = {classpath:META-INF/spring.xml}) in each test case, we create an AbstractTestCase with these annotations defined on it and extend this abstract class for all test cases. A sample can be found below:
/**
* An abstract test case with spring runner configuration, used by all test cases.
*/
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations =
{ "classpath:META-INF/spring.xml" })
public abstract class AbstractSampleTestCase
{
}
public class SampleTestOne extends AbstractSampleTestCase
{
#Resource
private SampleInterface sampleInterface;
#Test
public void test()
{
assertNotNull(sampleInterface);
}
}
public class SampleTestTwo extends AbstractSampleTestCase
{
#Resource
private SampleInterface sampleInterface;
#Test
public void test()
{
assertNotNull(sampleInterface);
}
}
#RunWith(Suite.class)
#SuiteClasses(
{ SampleTestOne.class, SampleTestTwo.class })
public class SampleTestSuite
{
}
If you don't want to have an AbstractSampleTest, then you need to repeat the spring runner annotations on each test case, until Spring comes up with a SpringJunitSuiteRunner similar to how they need to add a SpringJunitParameterizedRunner.

Spring 3+ How to create a TestSuite when JUnit is not recognizing it

I'm using Spring 3.0.4 and JUnit 4.5. My test classes currently uses Spring's annotation test support with the following syntax:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration (locations = { "classpath:configTest.xml" })
#TransactionConfiguration (transactionManager = "txManager", defaultRollback = true)
#Transactional
public class MyAppTest extends TestCase
{
#Autowired
#Qualifier("myAppDAO")
private IAppDao appDAO;
...
}
I don't really need the line extends TestCase to run this test. It's not needed when running this test class by itself. I had to add extends TestCase so that I can add it in a TestSuite class:
public static Test suite() {
TestSuite suite = new TestSuite("Test for app.dao");
//$JUnit-BEGIN$
suite.addTestSuite(MyAppTest.class);
...
If I omit the extends TestCase, my Test Suite will not run. Eclipse will flag suite.addTestSuite(MyAppTest.class) as error.
How do I add a Spring 3+ test class to a Test Suite? I'm sure there's a better way. I've GOOGLED and read the docs. If you don't believe me, I'm willing to send you all my bookmarks as proof. But in any case, I would prefer a constructive answer. Thanks a lot.
You are right; JUnit4-style tests should not extend junit.framework.TestCase
You can include a JUnit4 test as part of a JUnit3 suite this way:
public static Test suite() {
return new JUnit4TestAdapter(MyAppTest.class);
}
Usually you would add this method to the MyAppTest class. You could then add this test to your larger suite:
public class AllTests {
public static Test suite() {
TestSuite suite = new TestSuite("AllTests");
suite.addTest(MyAppTest.suite());
...
return suite;
}
}
You can create a JUnit4-style suite by creating a class annotated with Suite
#RunWith(Suite.class)
#SuiteClasses( { AccountTest.class, MyAppTest.class })
public class SpringTests {}
Note that AccountTest could be a JUnit4-style test or a JUnit3-style test.

Resources