Reputation: 4305
I have developed a web base application that in some way let's the user submit a test case just by inputting values instead of writing a complete JUnit test.
The way I used till now is generating a test class for each submission and then compile it and run.
For example assume we have a class like bellow:
public class CalculatorO
{
public boolean isPrime( int n )
{
if (n < 2) {
return false;
}
int count = 0;
for (int i = 1; i <= n; i++) {
if (n % i == 0) {
count++;
}
}
if (count == 2) {
return true;
} else {
return false;
}
}
}
As oracle, and another class like bellow:
public class CalculatorM0
{
public boolean isPrime( int n )
{
if (n < 2) {
return false;
}
int count = 0;
for (int i = 1; i <= n; i++) {
if (n * i == 0) {
count++;
}
}
if (count == 2) {
return true;
} else {
return false;
}
}
}
As subject of the test. Then I generate a test template as following:
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertArrayEquals;
import static org.unitils.reflectionassert.ReflectionAssert.assertReflectionEquals;
import org.junit.Test;
public class {{TestClassName}} {
@Test
public void {{MethodName}}() {
int AO = {{valueA}};
int AM = {{valueA}};
{{OriginalClassName}} {{OriginalClassNameLower}} = new {{OriginalClassName}}();
{{MutantClassName}} {{MutantClassNameLower}} = new {{MutantClassName}}();
{{MethodReturnType}} resultO = {{OriginalClassNameLower}}.{{MethodName}}(AO);
{{MethodReturnType}} resultM = {{MutantClassNameLower}}.{{MethodName}}(AM);
assertEquals(resultO, resultM);
}
}
Then for example when a user submits a number 3 as input value, I manipulate the test template like this:
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertArrayEquals;
import static org.unitils.reflectionassert.ReflectionAssert.assertReflectionEquals;
import org.junit.Test;
public class CalculatorOCalculatorM0Test30099 {
@Test
public void isPrime() {
int AO = 3;
int AM = 3;
CalculatorO calculatorO = new CalculatorO();
CalculatorM3 calculatorM3 = new CalculatorM3();
boolean resultO = calculatorO.isPrime(AO);
boolean resultM = calculatorM3.isPrime(AM);
assertEquals(resultO, resultM);
}
}
Then I compile the test case and run it.
The main issue is that this cycle occurs often and because of the load forced to the server, because of files being created and compiled, the server faces low memory issue and crashes much.
I am looking for a way to create the test case one time and build it one time then run it for each input with arguments.
I mean something like this:
java -cp .;../../JUnitLibs/junit-4.12.jar;../../JUnitLibs/hamcrest-core-1.3.jar org.junit.runner.JUnitCore CalculatorOCalculatorM0Test30099 > CalculatorOCalculatorM0Test30099Result -input 3
Upvotes: 2
Views: 2658
Reputation: 140613
One simple solution:
In other words: you call your testcase with some -Darg1:value1
values; and your testcase does lookup "arg1"; and stores the provided value into some fields AO and AM for example.
Of course, you have to rework your code a bit; and the tricky part might be about variable types here (properties are all strings; but you probably want int, float, ... variables). Going on step further, you could simply create a helper class that provides methods like:
public static class PropertyWrapper {
int getInt(String propertyName) { ...
and then you replace your pattern to something like
int AO = PropertyWrapper.getInt({{valueAPropertyName}});
Of course, this only works (easily) when you have different JVMs running the different user requests. Meaning: when you have two java runs, and give different args for each, then each unit test sees different values. When you have one JVM that is supposed to run this test multiple times with different arguments, then things become more complicated. You would then have that getInt() method have a list of values; and return one after the other; or something alike.
Upvotes: 1