This week's book giveaway is in the Agile and other Processes forum. We're giving away four copies of The Mikado Method and have Ola Ellnestam and Daniel Brolund on-line! See this thread for details.
A Simple Test Framework using JUnit and Spring (Part 1)
Ludwin Barbin
Greenhorn
Joined: Jul 29, 2009
Posts: 10
posted
0
This is a small framework that allows you to do unittesting on your POJOs under Spring environment. It is quite useful especially if you're adapting a Test-Driven Development methodoloy. This is Part 1 for testing service objects.
I will post a separate article in Part 2 for testing web pages and Spring Controller objects.
Only the following files are involved:
1. TestCase.java - the main class to extend for testing
2. AllTests.java - executes all test classes
3. LoginService.java - the class to be tested
4. LoginServiceTest.java - the test class for LoginService, contains all test cases
5. LoginServiceTestCase.java - the test case object for LoginService, executes test cases
6. applicationContext.xml - Spring configuration file
7. applicationContext-test.xml - Spring configuration file for test-specific beans
The package structure:
1. com.app.service.login - package for LoginService under /src folder
2. com.app.service.login - package for test classes for LoginService under /src-test folder, must be the same as the implementation class
3. com.test.main - package for test framework classes
Steps:
1. create a testcase object (LoginServiceTestCase) for a class to be tested (LoginService) by extending the TestCase.
2. create a test class (LoginServiceTest) which executes several test cases or scenarios - positive & negative test cases
3. modify AllTests class to include the LoginServiceTest class to be executed
4. modify applicationContext-test.xml to define the bean for LoginServiceTestCase
5. run the AllTests class as JUnit
Sample output:
Test Case: Validate Login with valid credentials
PASS: Validate Login with valid credentials
Test Case: Validate Login with empty credentials
PASS: Validate Login with empty credentials
Test Case: Validate Login with invalid credentials
PASS: Validate Login with invalid credentials
The jar files you need in your classpath:
spring.jar
spring-webmvc.jar
spring-test.jar
junit-4.5.jar
commons-logging.jar
ojdbc14.jar
You can use this framework to test for business logic objects, Data Access Objects, and other POJOs.
If you're connected to a database, it will write to a database and rollback the transaction after every test case.
You can use it to test for several classes at the same time by simply following the steps above for each class.
You can also invoke this from your build script to automatically do a test before deployment. It will give you an idea whether to proceed with deployment depending on which test cases have failed or succeeded.
It also serves as a documentation for your test cases. Just use javadoc to generate APIs and attach the execution output or the JUnit screen shot.
// execute the method to be tested, set the parameters or conditions before execute
protected abstract void executeTest() throws Exception;
// check actual results and store in appropriate results values, use the setActualResult() method
protected abstract void checkActualResults() throws Exception;
// check all expected results againts actual results
private boolean isResultsMatch() {
Iterator i = expectedResults.entrySet().iterator();
Map.Entry<String,Boolean> result;
while (i.hasNext()) {
result = (Map.Entry<String,Boolean>) i.next();
if (this.getExpectedResult(result.getKey()) != this.getActualResult(result.getKey())) return false;
}
return true;
}
// this to ensure that all result entries are compared
private void syncResults() {
int exp = expectedResults.size();
int act = actualResults.size();
if (exp == act) return;
Map.Entry<String,Boolean> result;
if (exp > act) {
Iterator i = expectedResults.entrySet().iterator();
while (i.hasNext()) {
result = (Map.Entry<String,Boolean>) i.next();
if (! actualResults.containsKey( result.getKey() ) ) {
actualResults.put(result.getKey(), false);
}
}
} else {
Iterator i = actualResults.entrySet().iterator();
while (i.hasNext()) {
result = (Map.Entry<String,Boolean>) i.next();
if (! expectedResults.containsKey( result.getKey() ) ) {
expectedResults.put(result.getKey(), false);
}
}
}
}
// reset all test conditions, and test results
public void initialize() {
testConditions.clear();
expectedResults.clear();
actualResults.clear();
}
// set conditions to specific value
public void setAllConditions(Object value) {
this.setMapValue(this.testConditions, value);
}
// set expected results to specific value
public void setAllExpectedResults(boolean value) {
this.setMapValue(this.expectedResults, value);
}
private void setMapValue(Map m, Object value) {
Iterator i = m.entrySet().iterator();
Map.Entry<String,Object> entry;
while (i.hasNext()) {
entry = (Map.Entry<String,Object>) i.next();
m.put(entry.getKey(), value);
}
}
// setters & getters
public void setTestCondition(String key, Object value)
{testConditions.put(key, value);}
public Object getTestCondition(String key)
{return testConditions.get(key);}
public void setExpectedResult(String key, Boolean value)
{expectedResults.put(key, value);}
public Boolean getExpectedResult(String key)
{return expectedResults.get(key);}
public void setActualResult(String key, Boolean value)
{actualResults.put(key, value);}
public Boolean getActualResult(String key)
{return actualResults.get(key);}
public String getTestName()
{return testName;}
public void setTestName(String testName)
{this.testName = testName;}
public boolean isValid(String username, String password) {
// change the ff code with a call to DAO which digest password
if (username.equals("ludwin") && password.equals("xyz")) return true;
return false;
}
}
public class LoginServiceTestCase extends TestCase {
@Autowired
private LoginService loginService; // the class to be tested
// conditions
protected final String CONDITION_USERNAME = "userName";
protected final String CONDITION_PASSWORD = "password";
protected final String RESULT_IS_ERROR = "isError";
Please UseCodeTags when posting code or configuration. Unformatted code and configuration is very difficult to read. You can edit your post to include them by using the button.
This seems more appropriate for a blog post, really. And it's not clear to me what your "framework" is, since JUnit is already a unit testing framework. What's your goal here? What problem are you trying to solve?