Passing arrays to Parameterized JUnit - java

I am new to parameterized feature of JUnit 4.x and having a problem. My parameterized test consists of 3 integer arrays and I am having difficulty of how to declare them. What I have below generates run-time error:
testGeneral[0] caused an ERROR: argument type mismatch
argument type mismatch
java.lang.IllegalArgumentException
at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
testGeneral[1] caused an ERROR: argument type mismatch
argument type mismatch
java.lang.IllegalArgumentException
at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
Here is my code:
#RunWith(Parameterized.class)
public class MyArrayTest {
private Integer[] inputList1;
private Integer[] inputList2;
private Integer[] expectedList;
public MyArrayTest(Integer[] li1, Integer[] li2, Integer[] expected) {
// ========> Runtime error happens here. <=========
this.inputList1 = li1;
this.inputList2 = li2;
this.expectedList = expected;
}
#Parameterized.Parameters
public static Collection testCases() {
return Arrays.asList(new Object[][][] {
{{1,1,1}, {2,2,2}, {3,3,3}},
{{2,2,2}, {3,3,3}, {4,4,4}}
});
}
#Test
public void testGeneral() {
// Do some test with this.inputList1, this.inputList2,
// and verify with this.expectedList
// I am not even getting here yet.
}
}
I appreciate your help to correctly passing the three arrays to my tests.

The reason why it is failing is because your test expects Integer arrays whereas you are passing Object type. So you are expanding the type. Try this:
#Parameterized.Parameters
public static Collection testCases() {
return Arrays.asList(new Integer[][][] {
{{1,1,1}, {2,2,2}, {3,3,3}},
{{2,2,2}, {3,3,3}, {4,4,4}}
});
}

This solution uses junitparams, implements junitparams.converters.Converter and parses list of long values as parameters.
package example;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Arrays;
import java.util.stream.Collectors;
import org.junit.Test;
import org.junit.runner.RunWith;
import junitparams.JUnitParamsRunner;
import junitparams.Parameters;
import junitparams.converters.ConversionFailedException;
import junitparams.converters.Converter;
import junitparams.converters.Param;
#RunWith(JUnitParamsRunner.class)
public class LongArrayParameterTest {
#Parameters({ "0|10", "1|10;20;30" })
#Test
public void test(final long otherParameter, #LongArrayParam final long[] expected) {
System.out.println(Arrays.stream(expected).boxed().map(l -> Long.toString(l)).collect(Collectors.toList()));
}
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.PARAMETER)
#Param(converter = LongArrayConverter.class)
public #interface LongArrayParam {
}
public static class LongArrayConverter implements Converter<LongArrayParam, long[]> {
#Override
public void initialize(final LongArrayParam annotation) {
}
#Override
public long[] convert(final Object param) throws ConversionFailedException {
final String str = (String) param;
final String[] longStrings = str.split(";");
return Arrays.stream(longStrings).mapToLong(s -> Long.parseLong(s)).toArray();
}
}
}
This parser does not support empty list.

Related

Rerunning parametrized JUnit test with string array parameter fails

While using parametrized JUnit tests in Eclipse, I'm running into a problem when I want to rerun a single test. The tests themselves run fine, and while I can rerun the first test from the context menu, rerunning the second test:
fails with the following message:
java.lang.Exception: No tests found matching [{ExactMatcher:fDisplayName=test[1: A2 --> [Ljava.lang.String;#1e4a7dd4]], {ExactMatcher:fDisplayName=test[1: A2 --> Ljava.lang.String;#1e4a7dd4]] from org.junit.internal.requests.ClassRequest#6c3f5566
I'm pretty sure this is because JUnit doesn't 'like' my arrays; for some context: I'm using this to account for the fact that due to external circumstances, the code under test can produce one of two outcomes for a particular test case.
Here is some code to reproduce this:
package com.stackexchange.toolbox;
import java.util.ArrayList;
import java.util.Arrays;
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 Tester {
public Tester(String source, Object target) {
this.source = source;
this.target = target;
}
private final String source;
private final Object target;
private static final Object[][] testCases = { { "A1", "B1" }, { "A2", new String[] { "B2", "C2" } } };
#Parameters(name = "{index}: {0} --> {1}")
public static Iterable<Object[]> data() throws Exception {
return new ArrayList<>(Arrays.asList(testCases));
}
#Test
public void test() throws Exception {
if (target instanceof String) {
Assert.assertEquals(source.charAt(1), ((String)target).charAt(1));
} else {
for (String target : (String[])this.target) {
Assert.assertEquals(source.charAt(1), target.charAt(1));
}
}
}
}
Is there an easy way to fix this, perhaps with Lists or variadic arguments? Most of the (100+) test cases are simple 'source', 'target' entries, and I'd like to keep the conciseness of { "A1", "B1" }.
This seems to be a limitation of JUnit4 (at least you get the same error on the command line).
The simplest and straightforward solution would be to migrate from JUnit4 to JUnit5, which would also mean less code:
package com.stackexchange.toolbox;
import java.util.Arrays;
import java.util.stream.Stream;
import org.junit.Assert;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
class Tester {
private static final Object[][] testCases = { { "A1", "B1" }, { "A2", new String[] { "B2", "C2" } } };
#ParameterizedTest(name = "{index}: {0} --> {1}")
#MethodSource("provideArguments")
void test(String source, Object target) {
if (target instanceof String) {
Assert.assertEquals(source.charAt(1), ((String)target).charAt(1));
} else {
for (String targetElement : (String[])target) {
Assert.assertEquals(source.charAt(1), targetElement.charAt(1));
}
}
}
static Stream<? extends Arguments> provideArguments() throws Exception {
return Arrays.stream(testCases).map(Arguments::of);
}
}

Parameterized junit test of custom validation in springboot

I have this validator in springboot which gives error when an integer is not between 1 and 3 and i am using addConstraintViolation to print a message from properties file
public class SizeValidator implements ConstraintValidator<SizeValidation, Integer> {
private int maxSize = 500;
private int minSize = 1;
#Override
public void initialize(SizeValidation constraintAnnotation) {
maxSize = constraintAnnotation.mxSize();
minSize = constraintAnnotation.minSize();
}
#Override
public boolean isValid(Integer givenSize, ConstraintValidatorContext context) {
if (givenSize > maxSize || givenSize<= minPageSize) {
addConstraintViolation(givenSize, "{Size.wrongSize.message}", context);
return false;
}
return true;
}
private void addConstraintViolation(Integer givenSize, String errorMessage, ConstraintValidatorContext context) {
final HibernateConstraintValidatorContext customContext = context.unwrap(HibernateConstraintValidatorContext.class);
customContext.addExpressionVariable("givenSize", givenSize);
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(errorMessage)
.addConstraintViolation();
}
}
and in my validation.properties
Size.wrongSize.message=Value of size ${givenSize} should be between 1
and 3
i wanted to write a Parameterized junit test for it as following but it returns nullpointerexception where am i doing wrong please?
java.lang.NullPointerException
at sizeValidator.addConstraintViolation(SizeValidator.java:33)
intellij says its at position
context.buildConstraintViolationWithTemplate(errorMessage)
.addConstraintViolation();
import org.hibernate.validator.constraintvalidation.HibernateConstraintValidatorContext;
import org.junit.Test;
import org.junit.experimental.runners.Enclosed;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import javax.validation.ConstraintValidatorContext;
import java.util.Arrays;
import java.util.Collection;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
#RunWith(Enclosed.class)
public class SizeValidatorTest{
#RunWith(Parameterized.class)
public static class TestValidEntries {
private SizeValidator validator = new SizeValidator();
private Integer val;
public TestValidEntries(Integer val) {
super();
this.val = val;
}
#Test
public void test() {
assertTrue(isValid(val));
}
#Parameterized.Parameters(name = "{index} Valid: {0}")
public static Collection data() {
return Arrays.asList(
-1, 501
);
}
public boolean isValid(Integer value) {
final HibernateConstraintValidatorContext context = mock(HibernateConstraintValidatorContext.class);
when(context.unwrap(HibernateConstraintValidatorContext.class)).thenReturn(context);
when(context.addExpressionVariable(eq("nonUnique"), anyString())).thenReturn(context);
when(context.getDefaultConstraintMessageTemplate()).thenReturn("template");
final ConstraintValidatorContext.ConstraintViolationBuilder builder = mock(ConstraintValidatorContext.ConstraintViolationBuilder.class);
when(context.buildConstraintViolationWithTemplate("template")).thenReturn(builder);
when(builder.addPropertyNode(anyString())).thenReturn(mock(ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext.class));
return validator.isValid(value, context);
}
}
}
The problem is in the configuration of the context mock.
Your configuration says:
when(context
.buildConstraintViolationWithTemplate(
"template"))
.thenReturn(builder);
But the string you pass in your code under test is: "{Size.wrongSize.message}"
Because this string do not match the mock returns null.
A better approach is to always use unspecific matchers like anyString() in the arrange part of the test method (or in setup) an specific matchers (or values) only in conjunction with Mockito.verify() in the assert part of the test method.

Getting the value of parameters passed in #Factory annotated class using TestNG

Is it possible to get the value of parameters that are used to initialize a #Factory annotated test class from any of the ITestListener, ISuiteListener or any other listener methods?
Below is a sample test class. My intention is to get the value of the class init parameter 'value' using any of the listener methods, possibly.
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Factory;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
import org.testng.reporters.EmailableReporter2;
#Listeners({ TestExecutionListener.class, EmailableReporter2.class })
public class TestClass {
private int value;
#Factory(dataProvider = "data", dataProviderClass = TestClass.class)
public TestClass(final int value) {
this.value = value;
}
#Test(alwaysRun = true)
public void testOdd() {
Assert.assertTrue(value % 2 != 0);
}
#Test(alwaysRun = true)
public void testEven() {
Assert.assertTrue(value % 2 == 0);
}
#DataProvider(name = "data")
public static Iterator<Object[]> data() {
List<Object[]> list = new ArrayList<>();
for (int i = 0; i < 2; i++) {
list.add(new Object[] { i });
}
return list.iterator();
}
}
Thanks in advance.
You can have access to your object from ITestResult#getInstance().
You'll just have to cast to object in the appropriate type (TestClass) and add a getter for value (or change its visibility).
ITestResult is available in many listeners.

Loops to populate JUnit Parameters?

I am trying to extract individual URLs from an array list and have them act as the arguments for a series of JUnit tests. However, thus far I have been unable to do so.
This project focuses on web testing, and the method I am using retrieves the HTTP status code for a given URL.
The code below is the parameters section from the JUnit Test. It accepts the URL and Expected value as inputs, and compares them to the actual vale to determine whether or not each passes.
#Parameters
public static Collection<Object[]> testData(){
Object[][] data = new Object[][]{{"http://google.com",200}, {"http://yahoo.com", 404}};
return Arrays.asList(data);
}
Does anybody have any experience on looping through list arrays with parametrized JUnit testing? Ex)
Object [][] data = new Object [][]{{urlArray.get(0), statusArray.get(0},....{urlArray.get(i), statusArray.get(i)}}
Thank you for any help you can provide!
Full code below:
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import org.junit.Test;
import org.junit.Before;
import org.junit.Assert;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
#RunWith(Parameterized.class)
public class CodeFinderTest extends CodeFinder {
private String url;
private int expected;
public CodeFinderTest(String url, int expected){
this.url = url;
this.expected = expected;
}
CodeFinder instance;
#Before
public void setup(){
instance = new CodeFinder();
}
#Parameters
public static Collection<Object[]> testData(){
Object[][] data = new Object[][]{{"http://google.com",200}, {"http://yahoo.com", 404}};
return Arrays.asList(data);
}
#Test
public void testFinder() throws IOException{
Assert.assertEquals(expected, instance.status(url));
}
}
The method that provides test data is a real method. Hence you can do this:
#Parameters
public static Collection<Object[]> testData(){
List<Object[]> data = new ArrayList<>();
Iterator<String> itUrl = urlArray.iterator();
Iterator<Integer> itStatus = statusArray.iterator();
while (itUrl.hasNext())
data.add(new Object [] {itUrl.next(), itStatus.next()});
return data;
}

How do you serialize Guava's immutable collections using Protostuff?

I use protostuff-runtime to serialize object graphs. Some of these objects have reference to Guava immutable collections, such as ImmutableList and ImmutableSet. Protostuff is unable to deserialize these collections out of the box, because it tries to construct an instance and then "add" elements to it from the inputStream (which fails, since the collections are immutable).
Do you know of any library / protostuff plugin that does that out of the box? If not, is there a best practice to do this myself?
I've investigated, and found that protostuff has a concept of "delegate", that lets you take control of the serialization for specific types. It seems to be the answer to my problem, but I can't seem to get it working.
Here is what I have right now:
import com.dyuproject.protostuff.Schema;
import com.dyuproject.protostuff.runtime.RuntimeSchema;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
/**
* This is the POJO I want to serialize. Note that the {#code strings} field refers to an {#link ImmutableList}.
*/
#Immutable
public class Foo {
public static final Schema<Foo> SCHEMA = RuntimeSchema.getSchema(Foo.class);
#Nonnull
private final ImmutableList<String> strings;
public Foo(ImmutableList<String> strings) {
this.strings = Preconditions.checkNotNull(strings);
}
#Nonnull
public ImmutableList<String> getStrings() {
return strings;
}
#Override
public boolean equals(Object obj) {
if (obj instanceof Foo) {
Foo that = (Foo) obj;
return this.strings.equals(that.strings);
}
return false;
}
#Override
public int hashCode() {
return strings.hashCode();
}
}
import com.dyuproject.protostuff.*;
import com.dyuproject.protostuff.runtime.Delegate;
import com.dyuproject.protostuff.runtime.RuntimeSchema;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import java.io.IOException;
import java.util.ArrayList;
public class ImmutableListDelegate implements Delegate<ImmutableList<?>> {
private static final Schema<ArrayList> LIST_SCHEMA = RuntimeSchema.getSchema(ArrayList.class);
#Override
public WireFormat.FieldType getFieldType() {
return WireFormat.FieldType.MESSAGE;
}
#Override
public ImmutableList<?> readFrom(Input input) throws IOException {
ArrayList<?> list = LIST_SCHEMA.newMessage();
input.mergeObject(list, LIST_SCHEMA);
return ImmutableList.copyOf(list);
}
#Override
public void writeTo(Output output, int number, ImmutableList<?> value, boolean repeated) throws IOException {
ArrayList<?> list = Lists.newArrayList(value);
output.writeObject(number, list, LIST_SCHEMA, repeated);
LIST_SCHEMA.writeTo(output, list);
}
#Override
public void transfer(Pipe pipe, Input input, Output output, int number, boolean repeated) throws IOException {
throw new UnsupportedOperationException("TODO");
}
#Override
public Class<?> typeClass() {
return ImmutableList.class;
}
}
import com.dyuproject.protostuff.LinkedBuffer;
import com.dyuproject.protostuff.ProtostuffIOUtil;
import com.dyuproject.protostuff.runtime.DefaultIdStrategy;
import com.dyuproject.protostuff.runtime.RuntimeEnv;
import com.google.common.collect.ImmutableList;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
public class ImmutableListDelegateTest {
#Before
public void before() {
// registers the delegate
if (RuntimeEnv.ID_STRATEGY instanceof DefaultIdStrategy) {
((DefaultIdStrategy) RuntimeEnv.ID_STRATEGY).registerDelegate(new ImmutableListDelegate());
}
}
#Test
public void testDelegate() throws IOException {
Foo foo = new Foo(ImmutableList.of("foo"));
Assert.assertEquals(foo, serializeThenDeserialize(foo));
}
private Foo serializeThenDeserialize(Foo fooToSerialize) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ProtostuffIOUtil.writeDelimitedTo(out, fooToSerialize, Foo.SCHEMA, buffer());
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
Foo fooDeserialized = Foo.SCHEMA.newMessage();
ProtostuffIOUtil.mergeDelimitedFrom(in, fooDeserialized, Foo.SCHEMA, buffer());
return fooDeserialized;
}
private LinkedBuffer buffer() {
return LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
}
}
The test fails with the following exception, which seems to mean that my delegate only deserializes null values:
java.lang.NullPointerException
at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:191)
at com.google.common.collect.SingletonImmutableList.<init>(SingletonImmutableList.java:40)
at com.google.common.collect.ImmutableList.asImmutableList(ImmutableList.java:305)
at com.google.common.collect.ImmutableList.copyFromCollection(ImmutableList.java:314)
at com.google.common.collect.ImmutableList.copyOf(ImmutableList.java:253)
at test.ImmutableListDelegate.readFrom(ImmutableListDelegate.java:25)
at test.ImmutableListDelegate.readFrom(ImmutableListDelegate.java:12)
at com.dyuproject.protostuff.runtime.RuntimeUnsafeFieldFactory$19$1.mergeFrom(RuntimeUnsafeFieldFactory.java:1111)
at com.dyuproject.protostuff.runtime.MappedSchema.mergeFrom(MappedSchema.java:188)
at com.dyuproject.protostuff.IOUtil.mergeDelimitedFrom(IOUtil.java:109)
at com.dyuproject.protostuff.ProtostuffIOUtil.mergeDelimitedFrom(ProtostuffIOUtil.java:151)
at test.ImmutableListDelegateTest.serializeThenDeserialize(ImmutableListDelegateTest.java:38)
at test.ImmutableListDelegateTest.testDelegate(ImmutableListDelegateTest.java:30)
Is this the right approach? What am I missing?
This is not a duplicate of the What is a Null Pointer Exception, and how do I fix it? question, which makes no sense. The fact that I mentioned that an NPE is thrown when trying to use a Protostuff delegate to de-serialize immutable collections, doesn't mean that this duplicates the "What is a NPE?" question in any way, shape, or form.
Everything looks fine and the
java.lang.NullPointerException
at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:191)
at com.google.common.collect.SingletonImmutableList.<init>(SingletonImmutableList.java:40)
says that you're trying to put null into an ImmutableList, which is forbidden. To be sure, inspect you list just before the failing line. Make sure your input json doesn't look like [null].

Categories