I've build a xquery Testframework, sometimes I want to test header and inbound and sometimes just Header for example.
I've got therefore 4 Testcases:
headerAndBody,
headerAndBodyTestsuite,
Header,
HeaderTestsuite
I search the directory for data and construct the tester from it.
And here is the Error:
#Test
public void someTest() throws Exception{
if (listHdrInbPayTestSuites.size() > 0) {
assertTrue(buildTest.testHdrInbPay(testSuiteIdentifier));
}
}
The list is EMPTY! but JUnit still says the test ran twice. How can I fix it to say it's an empty test?
Edit:
#Parameter
public String testSuiteIdentifier; (which actually has 2 items)
Edit:(One Testsuite can contain several testcases, so I can't just take another parameter, because I want to identify them by Testsuite name.)
Temporary solution:
Found a workaround to ignore these tests:
#Before
public void shouldRunTest() {
Assume.assumeTrue(listHeaderAndBodyTestSuites.size() > 0);
}
I'm not really satisfied with this solution since the information "test skipped" can be misleading.
Any other approaches/ideas?
JUnit does not support the concept of an empty test. An ignored test is the concept that comes closest to it.
In order to not increase the test count you have to ensure that the data values are not part of the parameters. This means you have to remove them within your #Parameters method. Here is an example that removes some data values for the Fibonacci test example of the Parameterized runner's documentation.
#Parameters
public static Iterable<Object[]> data() {
Collection<Object[]> currentData = Arrays.asList(
new Object[][] {
{ 0, 0 },
{ 1, 1 },
{ 2, 1 },
{ 3, 2 },
{ 4, 3 },
{ 5, 5 },
{ 6, 8 }
}
);
return currentData.stream()
.filter( dataSet -> dataSet[1] > 3 )
.collect( Collectors.toList() );
}
Related
Right now, I have around 107 test input cases for my interpreter, and I have my JUnit tester set up to manually handle each case independently so as to not lump them all together. That is, if I use a loop to iterate over the test files as such
for (int i = 0; i < NUM_TESTS; i++) {
String fileName = "file_" + (i + 1) + ".in";
testFile(fileName);
}
JUnit will create one giant test result for all 107 tests, meaning if one fails, the entire test fails, which I don't want. As I said, right now I have something like
#Test
public static void test001() {
testFile("file1.in");
}
#Test
public static void test002() {
testFile("file2.in");
}
While this works, I imagine there's a much better solution to get what I'm after.
You can use #ParameterizedTest with #MethodSource annotations.
For exemple :
#ParameterizedTest
#MethodSource("fileNameSource")
void test(final String fileName) {
testFile(fileName);
}
private static Stream<String> fileNameSource() {
return IntStream.range(0,NUM_TESTS).mapToObj(i -> "file_" + (i + 1) + ".in");
}
Check the documentation at https://junit.org/junit5/docs/current/user-guide/#writing-tests-parameterized-tests
For each params returned by fileNameSource(), the corresponding test will be considered as a different case.
You have to define own structure based on your need,
one way to define your input to json file in like list of values as below.
{
[
"value1",
"value2"
]
}
Read this value when you test case execute with the help of object mapper.
objectMapper.readValue(fixture("filePathName.json"),CustomInput.class);
Where CustomInput would be something like below.
public class CustomInput {
List<String> values;
}
You can keep increase & decrease your inputs in json.
I have a huge JSON-File which contains testcases. (No I don't wanna show it here because it doesn't matter in this case to know the file)
I parse the json file to my junit test - that works fine.
But I've got 50 testcases and if I want to show each in Junit like: "test 0 from 50 passed"
and have a list like: test 1 passed, test 2 passed, test 3 failed..
I have to put each testcase into a method. How can I dynamically do this? Is this possible in Junit? Because when I'm parsing the json, I don't know how many cases I have.
JUnit has direct support for CSV files, which means you can import and use them easily using #CSVFileSource.
However, since your case does not involve CSV files, I tried to create parametrized tests in JUnit 5 using JSON files.
Our class under test.
public class MathClass {
public static int add(int a, int b) {
return a + b;
}
}
Here's the JSON file I am using.
[
{
"name": "add positive numbers",
"cases": [[1, 1, 2],[2, 2, 4]]
},
{
"name": "add negative numbers",
"cases": [[-1, -1, -2 ], [-10, -10, -20 ]]
}
]
So, in JUnit 5 there is an annotation called #MethodSource which gives you the opportunity to provide arguments to your parametrized test. You only need to provide the method name. Here's my argument provider method.
#SneakyThrows
private static Stream<TestCase> getAddCases() {
final ObjectMapper mapper = new ObjectMapper();
TypeReference<List<Case>> typeRef = new TypeReference<>() {};
final File file = new File("src/test/resources/add-cases.json");
final List<Case> cases = mapper.readValue(file, typeRef);
return cases.stream()
.flatMap(caze -> caze.getCases()
.stream()
.map(el -> new TestCase(caze.getName(), el)));
}
In the code above, the class Case is used to map from the json object to Java Object and since the "cases" field is a multidimensional array, to represent each test case there is a class called TestCase. (Overall, this is not important for you, since you already are able to parse it, but I wanted to put it here anyway).
Finally, the test method itself.
#ParameterizedTest(name = "{index} : {arguments}")
#MethodSource("getAddCases")
void add_test(TestCase testCase) {
final List<Integer> values = testCase.getValues();
int i1 = values.get(0);
int i2 = values.get(1);
int e = values.get(2);
assertEquals(e, MathClass.add(i1, i2));
}
#ParametrizedTest annotation takes a name argument where you can provide a template for the test names. I just played around with the toString method of TestCase class to achieve a better description for each test case.
#Override
public String toString() {
return String.format("%s : (%s, %s) ==> %s", name, values.get(0), values.get(1), values.get(2));
}
And voila!
While Using TDD I found myself needing to test a constant (final) hashmap which contains lookup values (PLEASE SEE REASON WHY THIS WAS THE CASE UNDER UPDATE)
See below
private static final Map<Integer,String> singleDigitLookup = new HashMap<Integer, String>(){{
put(0,"Zero");put(1,"One");put(2,"Two");put(3,"Three");put(4,"Four");put(5,"Five");put(6,"Six");put(7,"Seven");
put(8,"Eight");put(9,"Nine");
}};
With TDD its stressed to test one thing at a time so i started calling my class verifying the validity of each of the elements as below.
TEST STYLE 1
#Test
public void whenWordIsOneThenReturn1(){
assertEquals(1, WordToIntegerConverter.toInteger("One"));
}
after writing the third test I thought it was pretty ridiculous and created a temporary lookup with the reverse key value pairs and began calling in a loop to test as below.
TEST STYLE 2
#Test
public void whenWordIsZeroThroughNineReturnIntegerConversion(){
HashMap<Integer, String> lookup = new HashMap<Integer, String>(){{
put(0,"Zero");put(1,"One");put(2,"Two");put(3,"Three");put(4,"Four");put(5,"Five");
put(6,"Six");put(7,"Seven");put(8,"Eight");put(9,"Nine");
}};
for(int i = 0; i < 10; i++) {
assertEquals(i, WordToIntegerConverter.toInteger(lookup.get(i)));
}
}
My Question is this; is it better to use style 1 for unit testing or is it better to use style 2.
I see pros and cons for both. for example style 1 is very concise, test only one thing and easier to understand. cons for style 1 besides doing a ton of typing the Test suite will blow up with many trivial test. Pros for style 2 is less unit tests. cons for style 2 has a bit of complexity and may be testing more than one thing but I would argue its only testing one thing the validity of the constant hashmap.
UPDATE
I've received a decent amount of blowback from this question so let me further explain. Its not the constant I care about per se but validating the different cases of my code. This Was a practice problem (Practicing TDD Via Katas) not production code. The problem was converting numbers to words so what I care about in my unit testing is ensuring I could properly handle the different possible numbers. There were other constants that I didn't include for example constant storing teen numbers (11, 12, 13...) and tensDigits(20, 30, 40...). Its fairly easy to make a typo here.
Approach #1 gets the job done, just with an obnoxious amount of cut-n-pasting. Approach #2 fixes that, but at the expense that the tests aren't independent: if one test fails the following ones don't run. Fixing one test just to find a bunch of new ones now fail is pretty annoying. You can improve on this by making a parameterized test, here's an example from junit's wiki:
#RunWith(Parameterized.class)
public class FibonacciTest {
#Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][] {
{ 0, 0 }, { 1, 1 }, { 2, 1 }, { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 }
});
}
private int fInput;
private int fExpected;
public FibonacciTest(int input, int expected) {
fInput= input;
fExpected= expected;
}
#Test
public void test() {
assertEquals(fExpected, Fibonacci.compute(fInput));
}
}
The parameterized test includes a collection of input/expected-output pairs, for each pair the input and output get passed into the constructor call for the test and the test method is called on the new test instance. The looping is kept in the test framework and out of the test, and each test succeeds or fails independently of the others.
I have following theory to test. In the code I want variable a to be Even and variable b to be odd
#RunWith(Theories.class)
public class TestJunit{
// add the error
#DataPoints
public static Integer[] integersOdd() {
return new Integer[]{1, 3, 5};
}
#DataPoints
public static Integer[] integersEven() {
return new Integer[]{2, 4, 6};
}
#Theory
public void testAdd(Integer a , Integer b) {
...
}
}
For now I am using assumeTrue and a validation function as in:
public boolean validateInput(Integer a, Integer b){
Set<Integer> even = new HashSet<Integer>(Arrays.asList(integersEven()));
Set<Integer> odd = new HashSet<Integer>(Arrays.asList(integersOdd()));
return (even.contains(a) && odd.contains(b));
}
Modified Theory:
#Theory
public void testAdd(Integer a , Integer b) {
Assume.assumeTrue(validateInput(a,b));
System.out.println("a="+a+", b="+b);
assertTrue(a+b>-1);
// add any test
}
It is a very dirty way as Java will pick all the combinations and will discard the inputs at assumeTrue. What If I have 10 theories with 10 datapoints? Java will try 100 combinations where I wanted only 10!
Is there neat way to do so? May be some annotation to tell JUnit to pick values for variables from which DataPoint?
Edit:
Another way I found is to use Test Generators. I am using JUnit-QuickCheck [Read Here] to generate random data according to the range required by my variables. Then I encapsulate them in a class and pass this object into my theory to test.
JUnit 4.12 allows for named data points in theories. Here's the original pull request, and here are the release notes for 4.12 - look for "Added mechanism for matching specific data points".
I'm writing Junit test cases for a bunch of classes; each of them has a handful of method to test. The classes I'm about to test look like the following.
class A{
int getNth(int n);
int getCount();
}
class B{
int[] getAllNth(int n);
int getMin();
}
I store the expected result for each class.method() in a file. For example, in a CSV,
A; getNth(1):7; getNth(2):3; getCount():3
B; getAllNth(2):[7,3]; getAllNth(3):[7,3,4]; getMin():3
My question is how can retrieve those value easily in test cases. I hope to pass the method call A.getNth(2) to a class that can build a string "A.getNth(2)"
If the format I store the data is not ideal, free feel to give suggestion on that as well.
It sounds like you might want to use Fitnesse?
Not sure about JUnit, but here is how you would do it with TestNG, using data providers:
#DataProvider
public Object[][] dp() {
return new Object[][] {
new Object[] { 1, 7 },
new Object[] { 2, 3 },
};
}
#Test(dataProvider = "dp")
public nthShouldMatch(int parameter, int expected) {
Assert.assertEquals(getNth(parameter), expected);
}
Obviously, you should implement dp() in a way that it retrieves its values from the spreadsheet instead of hardcoding them like I just did, but you get the idea. Once you have implemented your data provider, all you need to do is update your spreadsheet and you don't even need to recompile your code.