Warning: Parameter 1 to Language::getMagic() expected to be a reference, value given in /home/wikija5/public_html/w/includes/StubObject.php on line 58
Spring Test Context Framework - WikiJava
Wednesday, 23rd April 2014
Follow WikiJava on twitter now. @Wikijava

Spring Test Context Framework

From WikiJava

Jump to: navigation, search
The author suggests:

buy this book


Please visit Ganesh Gowtham's Website for other articles

Contents

Introduction

Level : Intermediate to advanced

For basic effective usage of Spring Framework Please visit

please visit For Usage of Spring frmk's wrapper class used for testing the spring beans which automatically rollbacks the transaction




Hi Folks ....

Today we will see how effectively we use the infrastructure provided by Spring's Testing Context framework with examples.

From Spring 2.5.X , couple of annotations were added in their testing portfolio in package "org.springframework.test.annotation".

What is Spring Test Context Framework The Spring TestContext Framework provides several abstract support classes that simplify the writing of integration tests. These base test classes provide well-defined hooks into the testing framework as well as convenient instance variables and methods

Which means spring provides infrastructure , when you can hook custom implementation testing frameworks like

The Spring Framework provides the following set of Spring-specific annotations that you can use in your unit and integration tests in conjunction with the TestContext framework.

Annotations

   * @IfProfileValue
   * @ProfileValueSourceConfiguration
   * @DirtiesContext
   * @ExpectedException
   * @Timed
   * @Repeat
   * @Rollback
   * @NotTransactional
   * @Autowired
   * @Qualifier

@IfProfileValue

@IfProfileValue - Useful in executing test methods based on system level variables value configured . Normally we write Junit Test classes which can run any environment ( DEV - Development , PRD -Production, UAT -User Acceptance Test , INT - Integration ) , based on configurations like db properties ....

You need to create the System variable in pc with Name PRJ_ENV and value will be depending our environment

@IfProfileValue(name="PRJ_ENV", value="DEV")
public void testProcessWhichRunsOnlyOnRestrictedEnv() {
    // some logic that should run only on Development environment
}

If you want to make this test run on both DEV , UAT , Here goes the configurations

@IfProfileValue(name="PRJ_ENV", values={"DEV","UAT"})
// Since we didnt annotate with @ProfileValueSourceConfiguration frmk will check in system variable ,Since by default it uses SystemProfileValueSource
public void testProcessWhichRunsOnlyOnRestrictedEnv() {
    // some logic that should run only on Development and UAT environment
}

@ProfileValueSourceConfiguration

If @ProfileValueSourceConfiguration is not present on the specified class or if a custom ProfileValueSource is not declared, the default SystemProfileValueSource will be returned instead

Class-level annotation which is used to specify what type of ProfileValueSource to use when retrieving profile values configured via the @IfProfileValue annotation. If @ProfileValueSourceConfiguration is not declared for a test, SystemProfileValueSource will be used by default.

SystemProfileValueSource - will read the system level variable if our case it is PRJ_ENV

If we want to tune in such a way that key value pair exits in properties file (or) db we need to write a class say i.e CustomProfileValueSource implements ProfileValueSource and override get(String key) then configuration would be like

@IfProfileValue(name="PRJ_ENV", values={"DEV","UAT"})
@ProfileValueSourceConfiguration(CustomProfileValueSource.class)
public void testProcessWhichRunsOnlyOnRestrictedEnv() {
    // some logic that should run only on Developement and UAT enviroment
}


@DirtiesContext

The presence of this annotation on a test method indicates that the underlying Spring container is 'dirtied' during the execution of the test method, and thus must be rebuilt after the test method finishes execution (regardless of whether the test passed or not).

@DirtiesContext
public void testSaveNewPerson() {
    // some logic that results in the Spring container being dirtied
	// which means during the execution you through the code , if we try to change the value of bean instantiated by spring
	// to reset the same we will annotate the next calling method with @DirtiesContext which loads all bean freshly
}

@ExpectedException

Indicates that the annotated test method is expected to throw an exception during execution. The type of the expected exception is provided in the annotation, and if an instance of the exception is thrown during the test method execution then the test passes. Likewise if an instance of the exception is not thrown during the test method execution then the test fails.

//Can be used for Negative testing 
@ExpectedException(UserNotFoundException.class)
public void testLoginProcess() {
    // some logic that should result in an Exception being thrown	
}

@Timed

Indicates that the annotated test method has to finish execution in a specified time period (in milliseconds). If the text execution time takes longer than the specified time period, the test fails.

//In EJB way , we have TimeOut configuration , after which transaction in EJB Context will be automatically roll backed
@Timed(millis=1000)
public void testResponseWithinSecond() {
    // some logic that should not take longer than 1 second to execute
}

@Repeat

Indicates that the annotated test method must be executed repeatedly. The number of times that the test method is to be executed is specified in the annotation. If in class if setUp() and tearDown() is overridden (or) method is annotated these methods will also be called as many times as

configured in @Repeat annotation
@Repeat(10)
public void testProcessRepeatedlyForTenTimes() {
    // ...
}

@Rollback

If you use AbstractTransactionalSpringContextTests , tx will be automatically rollback Please check my page regarding the usage of "AbstractTransactionalSpringContextTests" @Rollback Indicates whether or not the transaction for the annotated test method should be rolled back after the test method has completed. If true, the transaction will be rolled back; otherwise, the transaction will be committed. Use @Rollback to override the default rollback flag configured at the class level.

@Rollback(false) // read-only tx
public void testProcessWithoutRollback() {
    // ...
}

@NotTransactional

The presence of this annotation indicates that the annotated test method must not execute in a transactional context.

//( No need to transaction manager definition in spring xml )
@NotTransactional 
public void testProcessWithoutTransaction() {
    // ...
}

Spring Test Context Framework

In below style of spring junit applicationContext.xml will read from classpath

@RunWith(SpringJUnit4ClassRunner.class)
/*
Defines class-level metadata which is used to determine how to load and configure an ApplicationContext. Specifically, @ContextConfiguration defines the application context resource locations to load as well as the ContextLoader strategy to use for loading the context.
*/
@ContextConfiguration(locations = {"classpath:/com/googlecode/jpractices/applicationContext.xml"})
@TestExecutionListeners({DependencyInjectionTestExecutionListener.class})
public class UserServiceTest {
	/* Spring frmk will search is there any bean defined with TYPE of UserService to inject
	*/
    @Autowired
    private UserService userService;
    @Test
    public void doesUserExists() {
        boolean isUserExists = userService.doesUserExists("admin");
        assertTrue(true,isUserExists);
    }    
}

If bean declared in different name like <bean id="uSevice" class="com.jpractices.service.UserService" /> then we need to use @Qualifier in conjunction with @AutoWired like below

@Autowired
@Qualifier("uSevice")
private UserService userService;

@Qualifier can also be used in scenario's like , you had configured multiple datasources in spring xml and used spring autowiring super class for junit's to specify which datasource should be injected to which dao.

public void setDataSource(@Qualifier("myDataSource") DataSource dataSource) {
        super.setDataSource(dataSource);
}

Example from spring docuementation.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@TransactionConfiguration(transactionManager="txMgr", defaultRollback=false)
@Transactional
/* This class doesnt extend any spring frmk testing class like 'AbstractJUnit38SpringContextTests','AbstractTransactionalJUnit38SpringContextTests','AbstractTransactionalJUnit4SpringContextTests','AbstractTransactionalTestNGSpringContextTests' .... , instead it uses annotations )
public class FictitiousTransactionalTest {
 
/* Indicates that the annotated public void method should be executed before a transaction is started for test methods configured to run within a transaction via the @Transactional annotation.
*/
    @BeforeTransaction
    public void verifyInitialDatabaseState() {
        // logic to verify the initial state before a transaction is started
    }
 
    @Before
    public void setUpTestDataWithinTransaction() {
        // set up test data within the transaction
    }
 
    @Test
    // overrides the class-level defaultRollback setting
    @Rollback(true)
    public void modifyDatabaseWithinTransaction() {
        // logic which uses the test data and modifies database state
    }
 
    @After
    public void tearDownWithinTransaction() {
        // execute "tear down" logic within the transaction
    }
/*
Indicates that the annotated public void method should be executed after a transaction has been ended for test methods configured to run within a transaction via the @Transactional annotation.
*/
    @AfterTransaction
    public void verifyFinalDatabaseState() {
        // logic to verify the final state after transaction has rolled back
    }
 
    @Test
    @NotTransactional
    public void performNonDatabaseRelatedAction() {
        // logic which does not modify database state
    }
}

Comments from the users

To be notified via mail on the updates of this discussion you can login and click on watch at the top of the page


Comments on wikijava are disabled now, cause excessive spam.