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

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.

Related

How to order Tests while building Spring Boot application

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

How can I mock part of a Spring Boot service for ALL of my Spock Integration tests?

I am using Spock to create integration tests for my Spring Boot Application, but I'm having trouble figuring out how to mock part of a Service for all my test cases.
My app writes to an Azure Cosmos database running in Gremlin Graph mode, and since I don't know of any in-memory databases to adequately simulate it, I would like to make sure any service that writes to my development database only interacts with entities labeled with the current test's random UUID. So any service that reads/writes to the database needs to make sure to include the current test ID in any query.
What's the best way to mock a couple reused methods in an abstract base class via Spock?
GraphService.groovy <== The abstract class with some methods I wish to mock.
abstract class GraphService {
#Autowired
protected GraphTraversalSource g
protected GraphTraversal buildBaseQuery() {
return g.V()
}
protected GraphTraversal buildBaseCreationQuery(String label) {
return g.addV(label)
}
}
Several database searching/modifying services inherit the above class. For all of my tests, instead of g.V() I want g.V().has("testID", testId) and instead of g.addV(label) I want g.addV(label).property("testID", testId). How can I accomplish this across all my integration tests? I tried creating a base-specification class that specified this behavior, but it didn't work.
TestConfig.groovy
#Configuration
class TestConfig {
#Bean
#Primary
GraphPersistenceService persistenceService(
GraphTraversalSource g) {
DetachedMockFactory mockFactory = new DetachedMockFactory()
GraphPersistenceService persistenceService = mockFactory.Stub( //Mock doesn't work either
[constructorArgs: [g]], GraphPersistenceService)
return graphPersistenceService
}
}
BaseIntegrationTest.groovy
class BaseIntegrationTest extends Specification {
#Autowired
TestUtil testUtil
#Autowired
GraphTraversalSource g
#Autowired
GraphPersistenceService persistenceService
def setup() {
persistenceService.buildBaseQuery >> g.V().has("testID", testUtil.id)
persistenceService.buildBaseCreationQuery(_ as String) >> { label ->
g.addV(label).property("testID", testUtil.id)
}
}
def cleanup() {
testUtil.removeAllEntitiesWithCurrentTestId()
}
}
And then in an actual test:
#SpringBootTest(classes = MyGraphApplication.class)
#ContextConfiguration(classes = [GraphDbConfig.class, TestConfig.class])
#ActiveProfiles("test")
#TestPropertySource(locations = 'classpath:application-local.properties')
class UserOfPersistenceServiceSpec extends BaseIntegrationTest {
#Autowired
UserOfGraphPersistenceService userOfPersistenceService
def "Can create a bunch of vertices"() {
expect:
userOfPersistenceService.createABunchOfVertices() == 5
}
}
PS. I'm using Spring 1.5.10.RELEASE and groovy 2.4.15...
If upgrading to Spock 1.2 is an option for you, I suggest ditching the TestConfig class and using the #SpringBean annotation.
This is an example of how I have it set up in my tests:
#ActiveProfiles(["integrationtest"])
#DirtiesContext
abstract class IntegrationTest extends Specification {
#SpringBean
EurekaClient eurekaClient = Mock() {
getNextServerFromEureka(*_) >> Mock(InstanceInfo) {
getHomePageUrl() >> "test.test"
}
}
// ... other stuff
}

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.

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.

Reuse spring application context across junit test classes

We've a bunch of JUnit test cases (Integration tests) and they are logically grouped into different test classes.
We are able to load Spring application context once per test class and re-use it for all test cases in a JUnit test class as mentioned in http://static.springsource.org/spring/docs/current/spring-framework-reference/html/testing.html
However, we were just wondering if there is a way to load Spring application context only once for a bunch of JUnit test classes.
FWIW, we use Spring 3.0.5, JUnit 4.5 and use Maven to build the project.
Yes, this is perfectly possible. All you have to do is to use the same locations attribute in your test classes:
#ContextConfiguration(locations = "classpath:test-context.xml")
Spring caches application contexts by locations attribute so if the same locations appears for the second time, Spring uses the same context rather than creating a new one.
I wrote an article about this feature: Speeding up Spring integration tests. Also it is described in details in Spring documentation: 9.3.2.1 Context management and caching.
This has an interesting implication. Because Spring does not know when JUnit is done, it caches all context forever and closes them using JVM shutdown hook. This behavior (especially when you have a lot of test classes with different locations) might lead to excessive memory usage, memory leaks, etc. Another advantage of caching context.
To add to Tomasz Nurkiewicz's answer, as of Spring 3.2.2 #ContextHierarchy annotation can be used to have separate, associated multiple context structure. This is helpful when multiple test classes want to share (for example) in-memory database setups (datasource, EntityManagerFactory, tx manager etc).
For example:
#ContextHierarchy({
#ContextConfiguration("/test-db-setup-context.xml"),
#ContextConfiguration("FirstTest-context.xml")
})
#RunWith(SpringJUnit4ClassRunner.class)
public class FirstTest {
...
}
#ContextHierarchy({
#ContextConfiguration("/test-db-setup-context.xml"),
#ContextConfiguration("SecondTest-context.xml")
})
#RunWith(SpringJUnit4ClassRunner.class)
public class SecondTest {
...
}
By having this setup the context that uses "test-db-setup-context.xml" will only be created once, but beans inside it can be injected to individual unit test's context
More on the manual: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/testing.html#testcontext-ctx-management (search for "context hierarchy")
One remarkable point is that if we use #SpringBootTests but again use #MockBean in different test classes, Spring has no way to reuse its application context for all tests.
Solution is to move all #MockBean into an common abstract class and that fix the issue.
#SpringBootTests(webEnvironment = WebEnvironment.RANDOM_PORT, classes = Application.class)
public abstract class AbstractIT {
#MockBean
private ProductService productService;
#MockBean
private InvoiceService invoiceService;
}
Then the test classes can be seen as below
public class ProductControllerIT extends AbstractIT {
// please don't use #MockBean here
#Test
public void searchProduct_ShouldSuccess() {
}
}
public class InvoiceControllerIT extends AbstractIT {
// please don't use #MockBean here
#Test
public void searchInvoice_ShouldSuccess() {
}
}
Basically spring is smart enough to configure this for you if you have the same application context configuration across the different test classes. For instance let's say you have two classes A and B as follows:
#ActiveProfiles("h2")
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class A {
#MockBean
private C c;
//Autowired fields, test cases etc...
}
#ActiveProfiles("h2")
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class B {
#MockBean
private D d;
//Autowired fields, test cases etc...
}
In this example class A mocks bean C, whereas class B mocks bean D. So, spring considers these as two different configurations and thus would load the application context once for class A and once for class B.
If instead, we'd want to have spring share the application context between these two classes, they would have to look something as follows:
#ActiveProfiles("h2")
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class A {
#MockBean
private C c;
#MockBean
private D d;
//Autowired fields, test cases etc...
}
#ActiveProfiles("h2")
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class B {
#MockBean
private C c;
#MockBean
private D d;
//Autowired fields, test cases etc...
}
If you wire up your classes like this, spring would load the application context only once either for class A or B depending on which class among the two is ran first in the test suite. This could be replicated across multiple test classes, only criteria is that you should not customize the test classes differently. Any customization that results in the test class to be different from the other(in the eyes of spring) would end up creating another application context by spring.
create your configuaration class like below
#ActiveProfiles("local")
#RunWith(SpringJUnit4ClassRunner.class )
#SpringBootTest(classes ={add your spring beans configuration classess})
#TestPropertySource(properties = {"spring.config.location=classpath:application"})
#ContextConfiguration(initializers = ConfigFileApplicationContextInitializer.class)
public class RunConfigration {
private ClassLoader classloader = Thread.currentThread().getContextClassLoader();
private static final Logger LOG = LoggerFactory.getLogger(S2BXISINServiceTest.class);
//auto wire all the beans you wanted to use in your test classes
#Autowired
public XYZ xyz;
#Autowired
public ABC abc;
}
Create your test suite like below
#RunWith(Suite.class)
#Suite.SuiteClasses({Test1.class,test2.class})
public class TestSuite extends RunConfigration {
private ClassLoader classloader = Thread.currentThread().getContextClassLoader();
private static final Logger LOG = LoggerFactory.getLogger(TestSuite.class);
}
Create your test classes like below
public class Test1 extends RunConfigration {
#Test
public void test1()
{
you can use autowired beans of RunConfigration classes here
}
}
public class Test2a extends RunConfigration {
#Test
public void test2()
{
you can use autowired beans of RunConfigration classes here
}
}

Resources