I mostly write Selenium WebDriver tests in Java but I recently had to work on some Selenium tests written in Python using nose. I noticed a great nose tool that generates separate test cases while iterating over a set of values (e.g. for testing every item in a drop-down list and getting a result entry for each).
http://swordstyle.com/func_test_tutorial/part_one/extra_generative_tests.html
Is there something similar that I could use in junit?
Sure, take a look at the JUNIT Data Provider library
From the docs:
import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import com.tngtech.java.junit.dataprovider.DataProvider;
import com.tngtech.java.junit.dataprovider.DataProviderRunner;
import com.tngtech.java.junit.dataprovider.UseDataProvider;
#RunWith(DataProviderRunner.class)
public class DataProviderTest {
#DataProvider
public static Object[][] dataProviderAdd() {
// #formatter:off
return new Object[][] {
{ 0, 0, 0 },
{ 1, 1, 2 },
/* ... */
};
// #formatter:on
}
#Test
#UseDataProvider("dataProviderAdd")
public void testAdd(int a, int b, int expected) {
// Given:
// When:
int result = a + b;
// Then:
assertEquals(expected, result);
}
}
Related
I am trying to implement Parameterized test in which I have a set of input and expected values which I want to test using assertEquals method of JUnit. I'm using JUnit version 5.x for this I am passing the input value to my custom method defined in other package (that I'm testing) and I am checking it with an expected value with assertEquals method.
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.Arrays;
import java.util.Collection;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.runners.Parameterized.Parameters;
class StringHelperTest {
private StringHelper helper = new StringHelper();
private String input;
private String expectedOutput;
public String getInput() {
return input;
}
public void setInput(String input) {
this.input = input;
}
public String getExpectedOutput() {
return expectedOutput;
}
public void setExpectedOutput(String expectedOutput) {
this.expectedOutput = expectedOutput;
}
#Parameters
public static Collection<String[]> testConditions() {
String[][] expectedOutputs = { { "AACD", "CD" }, { "ACD", "CD" }, { "CDEF", "CDEF" }, { "CDAA", "CDAA" } };
return Arrays.asList(expectedOutputs);
}
#ParameterizedTest
#Test
public void truncateAInFirst2Positions_A_atStart() {
assertEquals(expectedOutput, helper.truncateAInFirst2Positions(input));
}
}
In the method testConditions() the actual and expected values are given as a 2 dimensinonal String array expectedOutputs {{<actual_value>,<expected_value>},{...}}.
How do I pass expectedOutputs array to the truncateAInFirst2Positions_A_atStart() method to test all conditions mentioned in expectedOutputs array
With JUnit 5 you have ParameterizedTest and a Source for the input parameters, which are simple the parameters of the method.
So you want a Method with this signature:
#ParameterizedTest
//Source Annotation
void truncateAInFirst2Positions_A_atStart(String actual, String expected) {
And now you look up a for your use case matching source. When you want to proivde your test data with your method you could use #MethodSource("testConditions"). The String in the annotation points to the static method providing your test data. The test will be executed x times where x is the count of pairs in your collection. The elements in your String Array will be used as method arguments.
For simple types like Strings a CSV source can be simpler and easier to read:
#CsvSource({
"AACD, CD",
"ACD, CD"
})
You can check all possible sources and possiblites in the offcial documentation:
https://junit.org/junit5/docs/current/user-guide/#writing-tests-parameterized-tests
Just for reference as the question is already answered, but if you need something else than strings (e.g. your own objects) you can use org.junit.jupiter.params.provider.Arguments.arguments, e.g.:
#ParameterizedTest
#MethodSource("provideMyObject")
void myTestMethod(ActualObject actual, ExpectedObject expected) {
// ...
}
static Stream<Arguments> provideMyObject() {
return Stream.of(
org.junit.jupiter.params.provider.Arguments.arguments(new ActualObject("foo"), new ExpectedObject("foo")),
org.junit.jupiter.params.provider.Arguments.arguments(new ActualObject("bar"), new ExpectedObject("bar))
);
}
see also: https://junit.org/junit5/docs/current/user-guide/#writing-tests-parameterized-tests-sources-MethodSource
I have written a simple class and test it manually in main() and works as expected:
import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.linalg.factory.Nd4j;
public class ND4J {
public static void main(String[] args) {
ND4J actualObject = new ND4J(Nd4j.zeros(2,2).add(4.0));
INDArray testObject = Nd4j.create(new double[][]{{4.0,4.0}, {4.0,4.0}});
if(testObject.equals(actualObject.getMatrix())){
System.out.println("OK"); // prints “OK”
}
}
private INDArray matrix;
public ND4J (INDArray matrix){
this.matrix = matrix;
}
public INDArray getMatrix(){
return this.matrix;
}
public String toString(){
return this.getMatrix().toString();
}
}
But trying to unit test this class with JUnit 4 is throwing java.lang.AbstractMethodError:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.linalg.factory.Nd4j;
import static org.junit.Assert.*;
public class ND4JTest {
#Test
public void print() {
ND4J actualObject = new ND4J(Nd4j.zeros(2,2).add(4.0));
//above statement throws this error
//java.lang.AbstractMethodError: org.nd4j.linalg.factory.Nd4jBackend.getConfigurationResource()Lorg/springframework/core/io/Resource;
INDArray testObject = Nd4j.create(new double[][]{{4.0,4.0}, {4.0,4.0}});
assertEquals(testObject, actualObject.getMatrix());
}
}
In fact more complex classes classes using ND4J that run fine from main() are having similar problems in testing. My pom file has the following ND4J dependencies: javacpp, nd4j-jblas, nd4j-native-platform, nd4j-native.
Thanks
Rather than the prerequisites mentioned on the ND4J get started page I got it working by following instructions from here: https://github.com/deeplearning4j/dl4j-examples/blob/master/standalone-sample-project/pom.xml
We are running Sonarqube 5.6.1 with the Java Plugin 4.1 and having some troubles using the Sonar rule S2699 (Test should include assertions).
Using this example test class
import mypackage.Citit1543Dummy;
import mypackage.Citit1543OtherDummy;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.MockitoAnnotations;
import java.util.Arrays;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.isIn;
import static org.hamcrest.Matchers.lessThan;
import static org.hamcrest.core.IsNot.not;
import static org.mockito.Matchers.notNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.junit.Assert.assertThat;
public class Citit1543Test {
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
#Test
public void test1() {
assert true;
}
#Test
public void test2() {
Assert.assertTrue(1 > (2-3));
}
#Test
public void test3() {
Assert.assertFalse(1 > (100-1));
}
#Test
public void test4() {
Assert.assertThat("test", 1, is(1));
}
#Test
public void test5() {
Assert.assertArrayEquals(new String[0], new String[0]);
}
#Test
public void test6() {
Assert.assertEquals(1 > 0, true);
}
#Test
public void test7() { // asserts in another method
test7asserts(1, 1);
}
private void test7asserts(int a, int b) {
Assert.assertTrue(a == b);
}
#Test
public void test8() {
test8asserts(1, 2);
}
private void test8asserts(int a, int b) {
Assert.assertNotSame(a, b);
}
#Test
public void test9() {
Citit1543Dummy dummy = new Citit1543Dummy();
dummy.otherDummy = mock(Citit1543OtherDummy.class);
dummy.doSomething();
verify(dummy.otherDummy, times(1)).doSomething();
}
#Test
public void test10() {
Citit1543Dummy dummy = new Citit1543Dummy();
dummy.otherDummy = mock(Citit1543OtherDummy.class);
dummy.doSomething();
test10verifies(dummy.otherDummy);
}
private void test10verifies(Citit1543OtherDummy otherDummy) {
verify(otherDummy, times(1)).doSomething();
}
#Test
public void test11() {
Assert.assertThat("test", "", not(1));
}
#Test
public void test12() {
Assert.assertThat("test", 1, lessThan(2));
}
#Test
public void test13() {
Long[] arr = new Long[] { 1L, 2L, 3L, 4L };
assertThat("Just testing", arr, is(new Long[] {
1L, 2L, 3L, 4L
}));
}
}
our Sonarqube instance flags the test cases test1 (assert statement not recognized), test7 (assert statements in another method), test8 (same) , test10 (Mockitos verify in another method), test11 and test13 as methods without assertions. I'm pretty sure that there are a lot more methods which aren't recognized (yes, unfortunately we use a bunch of different mocking/testing framework across our projects).
For now, we started to //NOSONAR whenever one of the asserts/verifies aren't recognized.
Is there an easy way to include these methods to be recognized as valid asserts?
Many of your stated issues are known and indeed (in some form of another) marked as FP:
test1: The current flow analysis ignores assert statements. See this post over at the groups.
The cases test7, test8 and test10 are related to the lack of not having cross-procedural analysis: They are valid cases but the current flow doesn't know that (ex.) test7assert is a valid assert statement for another method. See this post over at the groups.
Your other cases also produce false positives in the tests of S2699. I'd expect that once a SonarSource dev reads this topic that they'll create a ticket to resolve the cases in test11/13. But as I'm not a dev of them I can't guarantee that of course.
As to :
Is there an easy way to include these methods to be recognized as valid asserts?
No, the valid assertions are defined within the code of S2699 and are not a parameter. Some of your cases will require a more complex flow analysis whilst the last couple just seem to boil down to some missing definitions or too strict definitions, but I didn't deep-dive into the reasons why they produce FPs.
Is it possible to run a parameterized test class with JUnitCore API?
I've a class under test called Fibonacci, a parameterized test class called TestFibonacci, and a simple Java class (JUnitParameterized) which executes the TestFibonacci class using JUnitCore API. If I execute TestFibonacci with JUnit plugin or command line, it passes. However, when I execute it with my JUnitParameterized class it fails.
Class Under Test
public class Fibonacci {
public static int compute(int n) {
if (n <= 1) {
return n;
}
return compute(n-1) + compute(n-2);
}
}
Test Class
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import java.util.Arrays;
#RunWith(Parameterized.class)
public class TestFibonacci {
#Parameters(name = "{index}: fib({0})={1}")
public static Iterable<Object[]> data() {
return Arrays.asList(
new Object[][] { { 0, 0 }, { 1, 1 }, { 2, 1 }, { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 } });
}
private int input;
private int expected;
public TestFibonacci(int input, int expected) {
this.input = input;
this.expected = expected;
}
#Test
public void test() {
assertEquals(expected, Fibonacci.compute(input));
}
}
Java program
import org.junit.runner.JUnitCore;
import org.junit.runner.Request;
import org.junit.runner.Result;
public class JUnitParameterized {
public static void main(String[] args) throws ClassNotFoundException {
Class<?> testClass = JUnitParameterized.class.getClassLoader().loadClass(TestFibonacci.class.getCanonicalName());
Result result = (new JUnitCore()).run(Request.method(testClass, "test"));
System.out.println("Number of tests run: " + result.getRunCount());
System.out.println("The number of tests that failed during the run: " + result.getFailureCount());
System.out.println("The number of milliseconds it took to run the entire suite to run: " + result.getRunTime());
System.out.println("" + (result.wasSuccessful() == true ? "Passed :)" : "Failed :("));
}
}
When a JUnit test class is annotated with #Parameterized, the test method name as a description is enriched with a number in braces, colon, and the substituted name you're providing in the #Parameters annotation.
In your case, to execute single test, that is with one parameters set, you would
Result result = (new JUnitCore()).run(Request.method(TestFibonacci.class, "test[6: fib(6)=8]"));
In this case, the 6th parameter set is provided (starting with zero).
Note that, you must match exactly the numbers you're providing in the method name with what you declared as parameters. The sequence number also matters. As such following would not work:
"test[3: fib(6)=8]" (wrong sequence .. <6, 8> pair is 6th, not 3rd)
"test[6: fib(50)=100]" (the pair <50, 100> is not declared in parameters)
To avoid unnecessary parsing of the #Parameters(name=?) value, I would suggest to just declare the parameters without the name:
#Parameters // no name=?
public static Iterable<Object[]> data() {
return Arrays.asList(
new Object[][] { { 0, 0 }, { 1, 1 }, { 2, 1 }, { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 } });
}
And then the test method description is just test[6]:
Result result = (new JUnitCore()).run(Request.method(TestFibonacci.class, "test[6]"));
To run a single test method with all the parameters, I would suggest to do it in a cycle (and possibly aggregate the results):
int parametersCount = Request.aClass(TestFibonacci.class).getRunner().getDescription().getChildren().size();
for (int i = 0; i < parametersCount; ++i) {
Result result = (new JUnitCore()).run(Request.method(testClass, "testFloat[" + i + "]"));
System.out.println("Result " + result.wasSuccessful());
}
Instead of constantly creating identical debug configuraitons for my test cases, I would like to be able to simply save a few arguments common across all my Junit tests, right click on a specific test, then run that single run config. IE I would like a single debug configuration that can take as an argument the current selected test case instead of requiring me to manually specify it every time in the JUnit run configuration. My only options in the dialog appear to be either to specify a single test class or run all the tests in the project. As a result, Eclipse is littered with dozens of run configurations for all my test cases.
Instead of specifying a specific test class, I'd like it to specify a variable like ${container_loc} or ${resource_loc} for the class to run as in this question. Is there a variable in Eclipse that specifies the current selected Java class that I could place in the test class field in the dialog?
A specific example where this is useful is when running the Lucene unit tests. There's lots of arguments you can specify to customize the tests, some of which like -ea are required. Everytime I want to test a specific test case in Lucene in Eclipse, I have to manually setup these variables in the Eclipse debug config dialog :-/.
Have you looked at Parameterized Tests in JUnit? Here is an example:
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
#RunWith(Parameterized.class)
public class ParamTest {
#Parameters(name = "{index}: fib({0})={1}")
public static Iterable<Object[]> data() {
return Arrays.asList(new Object[][] {
{ 0, 0 }, { 1, 1 }, { 2, 1 }, { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 }
});
}
private int input;
private int expected;
public ParamTest(int input, int expected) {
this.input = input;
this.expected = expected;
}
#Test
public void test() {
Assert.assertEquals(expected, input);
}
}
If you just want to run one test at a time you can use private variables as in:
public class MultipleTest {
private int x;
private int y;
public void test1(){
Assert.assertEquals(x, y);
}
public void test2(){
Assert.assertTrue(x >y);
}
public void args1(){
x=10; y=1;
}
public void args2(){
x=1;y=1;
}
public void args3(){
x=1;y=10;
}
#Test
public void testArgs11(){
args1();
test1();
}
#Test
public void testArgs21(){
args2();
test1();
}
#Test
public void testArgs31(){
args3();
test1();
}
#Test
public void testArgs12(){
args1();
test2();
}
#Test
public void testArgs22(){
args2();
test2();
}
#Test
public void testArgs32(){
args3();
test2();
}
}