<img alt="" src="https://secure.leadforensics.com/150446.png " style="display:none;">

Externalizing Test Case Configuration While Unit Testing Spring Application

Nikhil Wanpal Nov 11, 2014

java solution consulting jee programming application Testing java application development java architecture consulting j2me application development jee5 software development jee software development Technology

Recently while testing a spring-based app, we required the ability to change the test case values frequently. We had the tests, mocking framework and test suites but we needed to have the ability to choose what values get passed to the test cases for the next run we trigger, especially for business use cases.

The usual habit was to have the JUnit test classes declare tests and assert, as anyone would do, but how would that change the inputs/expected values for a single run?
Enter - Externalizing the test case configuration!

One of the highlights of spring is DI: Dependency Inject a.k.a. Inversion of Control. That’s a ‘techy’ term for a simple (yet powerful) way to design classes, which means that the class allows its dependencies (Has-a) ‘injected’ in it at the time of instantiation. Well, we won’t be discussing what DI means here (I have made a promise that I will keep this and next few posts short!), there is plenty of documentation available online. But this just sets the context.

Lets assume that we want to test our class “Superb”, and our test class is “SuperbTest”

Let’s begin then. This is how our usual testContext.xml file would look like:

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config />
<context:component-scan base-package="com.demoapps" />
<context:property-placeholder location="classpath:TestCaseProps.properties" />
</beans>

Nothing special here or in the part that we are reading a TestConfigProps.properties file, but what that file has is somewhat interesting. And what does the properties file look like?

#Superb
Superb.input.users.user1=Nikhil
Superb.output.users.user1=Smart
Superb.input.users.user2=Nikhil2
Superb.output.users.user2=Wow
Superb.currentSetup.users=user1

We have to agree to a simple naming convention for the property names and we have an input/output matching pattern. The pattern dictates that we retain the category (“users”) and the id (“1”/”2”) across the input and output groups and we can match them to test output.

The last part of the puzzle:

package com.demoapps;
// imports
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations= {"classpath:testContext.xml"}) // and others, if you have.
public class SuperbTest {
@Value("${Superb.input.users.${Superb.currentSetup.users}}")
String testInput;
@Value("${Superb.output.users.${Superb.currentSetup.users}}")
String testOutput;
@Test
public void myTest() {
assertEquals(SomeClass.someAwesomeMethod(testInput), testOutput);
}
}

That was simple.
This method lets us externalize simple input and output values for tests. Although this lets us externalize output values, we now realize that we use it more to externalize only the inputs. Especially in cases where the inputs need to change from time to time. Also, it works best with Strings - other types, not so much.

A drawback of this method is that it works only with simple types. You cannot externalize large objects this way. But maybe it can be enhanced to accept paths to serialized objects instead.

Similar Blog

e-Zest is a leading digital innovation partner for enterprises and technology companies that utilizes emerging technologies for creating engaging customers experiences. Being a customer-focused and technology-driven company, it always helps clients in crafting holistic business value for their software development efforts. It offers software development and consulting services for cloud computing, enterprise mobility, big data and analytics, user experience and digital commerce.