ParametrizedTest with displayName and Argument - java

I am trying to migrate from JUnit4 to JUnit5 and also I'm new to ParametrizedTest in Junit5 and I have a scenario wherein I would like to provide different DisplayName and the Test argument(Object).
Here's the data source I would like to use as an input for #MethodSource("data")
public static Collection<Object[]> data() throws IOException {
List<Object[]> testCaseData = new ArrayList<>();
TestCaseReader testCaseReader = new TestCaseReader(TESTCASE_CSV_RESOURCE);
List<MyClass> testCaseList = testCaseReader.readTestCases();
for (MyClass testCase : testCaseList) {
if (testCase.isActive()) {
Object[] testParameter = new Object[2];
testParameter[0] = String.format("%03d: %s", testCase.getStartingLineNumber(), testCase.getName());
testParameter[1] = testCase;
testCaseData.add(testParameter);
}
}
return testCaseData;
}
And this is the Test
#ParameterizedTest(name = "Scenario: {0}, testCase={1}")
#MethodSource("data")
public void process(MyClass testCase) {
//...
//some operating on testCase methods/variables
}
When executing TestCase, I see the DisplayName is picked up correctly, but the other arguments is not resolvable it says
org.junit.jupiter.api.extension.ParameterResolutionException: Failed to resolve parameter [com.sample.MyClass testCase] in method [public void.MultipleTestCase.process(com.sample.MyClass testCase)]
Could you please guide me what I have done wrong here!
Thanks

Providing test data as Collection<Object[]> is no longer the appropriate way in JUnit 5. You can use a Stream instead. If you need to provide multiple parameters for your test you can use Arguments to wrap them. They are automatically unwrapped upon test execution. The example below gives a general idea on how to do that. You can replace TestCase with MyClass and insert your TestCaseReader code in data.
public class ParameterizedTest {
static Stream<Arguments> data() {
// TODO: Add your TestCaseReader usage to create MyClass / TestCase instances.
List<TestCase> testCases =
List.of(new TestCase("test01", "data01"), new TestCase("test02", "data02"));
return testCases.stream().map(test -> Arguments.arguments(test.getName(), test));
}
#org.junit.jupiter.params.ParameterizedTest(name = "Scenario: {0}, testCase={1}")
#MethodSource("data")
public void process(String name, TestCase testCase) {
System.out.println(name + ": " + testCase.getData());
// TODO: Work with your test case.
}
private static final class TestCase {
private final String name;
private final String data;
public TestCase(String name, String data) {
this.name = name;
this.data = data;
}
public String getName() {
return name;
}
public String getData() {
return data;
}
}
}

Related

Mocking method taking a Supplier<String> method not working

Given the following classes:
class Logger {
public void log(String someInfo,
String someOtherInfo,
VssNotificationStatus status,
Supplier<String> message)
{}
}
class Asset {
private String name;
private String alias;
Asset(String name, String alias) {
this.name = name;
this.alias = alias;
}
public String getName() {
return name;
}
public String getAlias() {
return alias;
}
}
class ClassUnderTest {
private Logger logger;
ClassUnderTest(Logger logger) {
this.logger = logger;
}
public void methodUnderTest(Asset asset) {
logger.log(asset.getName(), asset.getAlias(), VssNotificationStatus.ASSET_PREPARED, () -> String.format("%s is running", "methodUnderTest"));
}
}
And the following test code:
#RunWith(MockitoJUnitRunner.class)
public class TestA {
private ClassUnderTest clazz;
#Mock
private Logger logger;
#Before
public void setup() {
clazz = new ClassUnderTest(logger);
}
#Test
public void test() {
// given
String info1 = "info1";
String info2 = "info2";
Asset asset = mock(Asset.class);
given(asset.getName()).willReturn(info1);
given(asset.getAlias()).willReturn(info2);
// when
clazz.methodUnderTest(asset);
// then
verify(logger).log(eq(asset.getName()), eq(asset.getAlias()), eq(VssNotificationStatus.ASSET_PREPARED), any());
}
}
fails at the verify line with
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
0 matchers expected, 1 recorded
I tried to use isA(Supplier.class), specify Supplier.class in the any method, but still same error. It feels like Mockito is not mocking properly this method.
Those failing tests were passing properly before refactoring the last parameter from simple String parameter to a Supplier<String>.
I'm using mockito-core 2.13.0
It looks like Matchers doesn't like when you pass in a mocked method instead of using the value you used when mocking this method directly. The following verify works perfectly fine.
verify(logger).log(eq(info1), eq(info2), eq(VssNotificationStatus.ASSET_PREPARED), any());
So matchers should use real values and not getting them from a mocked object.

Run multiple tests with Selenium DataProvider

I am currently using testng + selenium to automate my tests, and I have the following scenario:
I need to read from an excel file, transform each row in an object and run 1 test for each of them. I am trying to use annotation #DataProvider to return an Array of objects, however it is only able to return Iterators and Objects[][]. Is there any workaround I can use to return an array of Cliente objects from the DataProvider? I have tried the following code, however it only prints the data from Client2:
public class TestDataProvider
{
Cliente cliente;
#DataProvider(name = "test1")
public static Object[][] dataMethod() {
return new Object[][] { { new Cliente("Client1", "1111111111") },
{ new Cliente("Client2", "2222222222") }};
}
#Test(dataProvider = "test1")
public void testMethod(Cliente cliente) {
System.out.println(cliente.getNome() + " " + cliente.getCartao());
}
}
Edit1: Cliente class:
public class Cliente {
private static String name;
private static String card;
//Construtor method
public Cliente(String name, String card){
setname(name);
setCartao(card);
}
public String getName() {
return name;
}
public void setName(String name) {
Cliente.name = name;
}
public String getCard() {
return card;
}
public void setCard(String card) {
Cliente.card = card;
}
}
Values that are printed in the console:
Client2 2222222222
Client2 2222222222
So...
Your prerequisites:
excel file, each row - one dataset
run test for each dataset
What can you do:
Create #DataProvider which return Iterator<Object[]> with your datasets where each Object[] is your row from excel. (the easiest one)
Use #Factory to manually iterate through your datasets and call test methods.
Use #DataProvider to provide data for #Factory and do as above.
The 2nd and 3rd options are complicated, but have some benefits if you has other parameters, except datasets, to run tests.
thanks for the help. With RocketRacoon's third suggestion I managed to resolve my problem. Below is a simple example:
public class ProvidedTest
{
private static nome;
private static cpf;
private static cartao;
#DataProvider
public static Object[][] dataProviderMethod() {
return new Object[][] { {"Client1", "111111111", "444444444"},
{"Client2", "222222222", "555555555"},
{"Client3", "333333333", "666666666"}};
}
#Factory (dataProvider="dataProviderMethod")
public ProvidedTest(String nome, String cpf, String cartao){
this.nome = nome;
this.cpf = cpf;
this.cartao = cartao;
}
#Test
public void testCase(){
System.out.println(cliente.getNome());
System.out.println(cliente.getCpf());
System.out.println(cliente.getCartao());
}
}

Design - Check a condition before executing every method

I have a POJO named Document.java with 100+ member variables. There is a transformation layer, where I get the required data, transform it and store it in the Document class.
In the tranformation layer, I would like to set a member variable only if satisfies a certain criteria (based on available context).
So it would look something like this:
if(shouldGetExecuted1(context.getXXX())){
document.setField1(tranformDataForField1(availableData1));
}
if(shouldGetExecuted2(context.getXXX())){
document.setField2(tranformDataForField2(availableData2));
}
I want to do this for all the 100+ fields. Is there a clean way to do this?
Additional information
I don't want to use Strategy here as it would create too many classes as the no of strategies grow.
Try to use AOP. AspectJ allows you to define pointcuts (for example, some filtered set of methods) and control their execution via advices (before method call, after, around):
#Aspect
class ClassName {
...
#PointCut("call(public void ClassName.*(..))") //includes all void methods of ClassName object
public void myPointCut(){}
#Around("myPointCut()")
public void myLogicMethod(ProceedingJoinPoint thisJoinPoint) {
if(shouldGetExecuted1(context.getXXX())){
thisJoinPoint.proceed()
}
}
}
Here thisJoinPoint.proceed() will execute the body of the intercepted method.
Read docs about how to define pointcuts. In this example the same logic will be applied to all void methods of this class. You can define more accurate pointcuts via special expressions to provide different logic for each.
No, there is no clean way to do it in Java. You can find methods using reflection but there is no way to find variables such as "availableDataN". So you necessarily need to make "availableDataN" a field in order to find it using reflection.
The final code would be something as ugly as the following:
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class X {
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
Method shouldGetExecuted = X.class.getMethod("shouldGetExecuted" + i, String.class);
boolean b = (boolean) shouldGetExecuted.invoke(null, context.getXXX());
if (b) {
Method tranformDataForField = X.class.getMethod("tranformDataForField");
Field data = X.class.getField("availableData" + i);
Object result = tranformDataForField.invoke(null, data.get(null));
Method set = X.class.getMethod("setField" + i, TransformDataType.class);
set.invoke(null, result);
}
}
}
}
You need to adapt to your specific case. For instance, here I am assuming all fields and methods are static. If they are not, then you need to replace null with an instance reference.
If you are consistent in the naming of your methods, reflection could help a lot.
The following code assumes the following:
A Document class with fields like xxx or xxYy (getters/setters would be usually present but are not required for the code to work)
A Transformer class that has
the capability to determine based on context information, if a field should be processed. These methods are named shouldTransformXxx(context).
the capability to transform the content of the field (with input and output of the same type as the corresponding field in Document). These methods are named T transformXxx(T).
A DataProvider class that has methods to provide the untransformed data. these methods are named findXxx()
The code below is pretty optimistic - it will fail, if a shouldTransformXxx for any field misses, or if it returns true, the same applies for the findXxx and transformXxx methods. So you would have to create classes with 100 methods each, which seems non-ideal for me. But on the other hand, having a class with 100 members seems to lead to awkward situations anyway...
So here's the code:
public class Document {
private String name;
private int size;
#Override
public String toString() {
return "Document [name=" + name + ", size=" + size + "]";
}
}
public class Transformer {
public enum ContextType {
NAME, SIZE
}
public boolean shouldTransformName(Set<ContextType> context) {
return context.contains(ContextType.NAME);
}
public boolean shouldTransformSize(Set<ContextType> context) {
return context.contains(ContextType.SIZE);
}
public String transformName(String name) {
return "::" + name;
}
public int transformSize(int size) {
return size + 1;
}
}
public class DataProvider {
private final String name;
private final int size;
public DataProvider(String name, int size) {
this.name = name;
this.size = size;
}
public String findName() {
return name;
}
public int findSize() {
return size;
}
}
public class Main {
private static final String TRANSFORM_METHOD_PREFIX = "transform";
private static final String CHECK_METHOD_PREFIX = "shouldTransform";
private static final String DATAPROVIDER_METHOD_PREFIX = "find";
private final DataProvider dataProvider;
private final Transformer transformer;
public Main(DataProvider dataProvider, Transformer transformer) {
this.dataProvider = dataProvider;
this.transformer = transformer;
}
public Document transformFields(Set<ContextType> context)
throws ReflectiveOperationException {
Document document = new Document();
for (Field field : Document.class.getDeclaredFields()) {
String capitalizedfieldName = capitalize(field.getName());
Class<?> fieldType = field.getType();
if (shouldTransform(context, capitalizedfieldName)) {
Object data = findData(capitalizedfieldName);
Object transformed = transformData(capitalizedfieldName,
fieldType, data);
// in presence of a security manager, a reflective call of the
// setter could be performed
field.setAccessible(true);
field.set(document, transformed);
}
}
return document;
}
private Object transformData(String capitalizedfieldName,
Class<?> fieldType, Object data)
throws ReflectiveOperationException {
String methodName = TRANSFORM_METHOD_PREFIX + capitalizedfieldName;
Method method = Transformer.class.getMethod(methodName, fieldType);
return method.invoke(transformer, data);
}
private Object findData(String capitalizedfieldName)
throws ReflectiveOperationException {
String methodName = DATAPROVIDER_METHOD_PREFIX + capitalizedfieldName;
Method method = DataProvider.class.getMethod(methodName);
return method.invoke(dataProvider);
}
private boolean shouldTransform(Set<ContextType> context,
String capitalizedfieldName) throws ReflectiveOperationException {
String methodName = CHECK_METHOD_PREFIX + capitalizedfieldName;
Method method = Transformer.class.getMethod(methodName, Set.class);
return (Boolean) method.invoke(transformer, context);
}
private String capitalize(String fieldName) {
char upperCaseFirstChar = Character.toUpperCase(fieldName.charAt(0));
if (fieldName.length() > 1) {
return upperCaseFirstChar + fieldName.substring(1);
} else {
return Character.toString(upperCaseFirstChar);
}
}
public static void main(String[] args) throws ReflectiveOperationException {
DataProvider dataProvider = new DataProvider("sample", 1);
Set<ContextType> context = EnumSet.of(ContextType.NAME,
ContextType.SIZE);
Main main = new Main(dataProvider, new Transformer());
Document document = main.transformFields(context);
System.out.println(document);
}
}

Annotation is null on run-time

I try to test out how an Annotation works, but doesn't go as planned. When I try to run the application everything works fine, unless the fact that ReadCommandAnnotation class is not able to retrieve the values from the Annotation from a method or class.
Now, I do not entirely know how to really do this, and I'm open for help and tips how to improve this. I have a plan why I want to use this, but right now I'm stuck at this point.
Example of what doesn't work: command, description, aliases, rank, useable
TL;DR, I want to retrieve the value from annotations from each method/class. I dont understand how to do it myself..
Register all the annotation values within this class.
public class ReadCommandAnnotation {
private final Class<?> clazz;
private String command;
private String[] description;
private boolean useable;
private String[] aliases;
private int rank;
public ReadCommandAnnotation(final Class<?> clazz) {
this.clazz = clazz.getClass();
this.register();
}
public void register() {
Method[] methods = clazz.getClass().getMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(CommandAnnotation.class)) {
CommandAnnotation commandAnnotation = method.getAnnotation(CommandAnnotation.class);
this.command = commandAnnotation.command();
this.description = commandAnnotation.description();
this.useable = commandAnnotation.use();
this.rank = commandAnnotation.rankRequired();
this.alises = commandAnnotation.aliases();
}
}
}
Annotation inferface, I think everything shoud be as normal here..?
#Retention(RetentionPolicy.RUNTIME)
public #interface CommandAnnotation {
String DEFAULT_MESSAGE = "N/A";
int DEFAULT_INTEGER = 1;
String command() default DEFAULT_MESSAGE;
String[] aliases() default { DEFAULT_MESSAGE };
String[] description() default { DEFAULT_MESSAGE };
int rankRequired() default DEFAULT_INTEGER;
boolean use() default true;
The "main" class. (onEnable) method is where I run everything. (SPONGE API IS IMPLEMENTED)
#Override
public void onEnable() {
testCommandAnnotation();
}
#Override
public void onDisable() {
}
#CommandAnnotation(command = "testCommand" , aliases = {"fancyCommand", "coolCommand"} , description = {"A test command execution.."} , rankRequired = 30, use = true)
public void testCommandAnnotation() {
ReadCommandAnnotation readAnnotation = new ReadCommandAnnotation(this.getClass());
readAnnotation.register();
System.out.println("Command: " + readAnnotation.getCommand());
}
Somehow when I execute this all I get up is a "N/A" in the console.

Capturing method parameter in jMock to pass to a stubbed implementation

I wish to achieve the following behavior.
My class under test has a dependency on some other class, I wish to mock this dependency with jMock. Most of the methods would return some standard values, but there is one method, where I wish to make a call to a stubbed implementation, I know I can call this method from the will(...) but I want the method to be called by the exact same parameters that were passed to the mocked method.
Test
#Test
public void MyTest(){
Mockery context = new Mockery() {
{
setImposteriser(ClassImposteriser.INSTANCE);
}
};
IDependency mockObject = context.mock(IDependency.class);
Expectations exp = new Expectations() {
{
allowing(mockObject).methodToInvoke(????);
will(stubMethodToBeInvokedInstead(????));
}
};
}
Interface
public interface IDependency {
public int methodToInvoke(int arg);
}
Method to be called instead
public int stubMethodToBeInvokedInstead(int arg){
return arg;
}
So how do I capture the parameter that were passed to the method being mocked, so I could pass them to the stubbed method instead?
EDIT
Just to give another example, let's say I wish to mock the INameSource dependency in the following (C#) code, to test the class Speaker
public class Speaker
{
private readonly string firstName;
private readonly string surname;
private INameSource nameSource ;
public Speaker(string firstName, string surname, INameSource nameSource)
{
this.firstName = firstName;
this.surname = surname;
this.nameSource = nameSource;
}
public string Introduce()
{
string name = nameSource.CreateName(firstName, surname);
return string.Format("Hi, my name is {0}", name);
}
}
public interface INameSource
{
string CreateName(string firstName, string surname);
}
This is how it can be done in Rhino Mocks for C# I understand it can't be as easy as this since delegates are missing in Java
The solution from Duncan works well, but there is even a simpler solution without resort to a custom matcher. Just use the Invocation argument that is passed to the CustomActions invoke method. At this argument you can call the getParameter(long i) method that gives you the value from the call.
So instead of this
return matcher.getLastValue();
use this
return (Integer) invocation.getParameter(0);
Now you don't need the StoringMatcher anymore: Duncans example looks now like this
#RunWith(JMock.class)
public class Example {
private Mockery context = new JUnit4Mockery();
#Test
public void Test() {
final IDependency mockObject = context.mock(IDependency.class);
context.checking(new Expectations() {
{
// No custom matcher required here
allowing(mockObject).methodToInvoke(with(any(Integer.class)));
// The action will return the first argument of the method invocation.
will(new CustomAction("returns first arg") {
#Override
public Object invoke(Invocation invocation) throws Throwable {
return (Integer) invocation.getParameter(0);
}
});
}
});
Integer test1 = 1;
Integer test2 = 1;
// Confirm the object passed to the mocked method is returned
Assert.assertEquals((Object) test1, mockObject.methodToInvoke(test1));
Assert.assertEquals((Object) test2, mockObject.methodToInvoke(test2));
}
public interface IDependency {
public int methodToInvoke(int arg);
}
Like Augusto, I'm not convinced this is a good idea in general. However, I couldn't resist having a little play. I created a custom matcher and a custom action which store and return the argument supplied.
Note: this is far from production-ready code; I just had some fun. Here's a self-contained unit test which proves the solution:
#RunWith(JMock.class)
public class Example {
private Mockery context = new JUnit4Mockery();
#Test
public void Test() {
final StoringMatcher matcher = new StoringMatcher();
final IDependency mockObject = context.mock(IDependency.class);
context.checking(new Expectations() {
{
// The matcher will accept any Integer and store it
allowing(mockObject).methodToInvoke(with(matcher));
// The action will pop the last object used and return it.
will(new CustomAction("returns previous arg") {
#Override
public Object invoke(Invocation invocation) throws Throwable {
return matcher.getLastValue();
}
});
}
});
Integer test1 = 1;
Integer test2 = 1;
// Confirm the object passed to the mocked method is returned
Assert.assertEquals((Object) test1, mockObject.methodToInvoke(test1));
Assert.assertEquals((Object) test2, mockObject.methodToInvoke(test2));
}
public interface IDependency {
public int methodToInvoke(int arg);
}
private static class StoringMatcher extends BaseMatcher<Integer> {
private final List<Integer> objects = new ArrayList<Integer>();
#Override
public boolean matches(Object item) {
if (item instanceof Integer) {
objects.add((Integer) item);
return true;
}
return false;
}
#Override
public void describeTo(Description description) {
description.appendText("any integer");
}
public Integer getLastValue() {
return objects.remove(0);
}
}
}
A Better Plan
Now that you've provided a concrete example, I can show you how to test this in Java without resorting to my JMock hackery above.
Firstly, some Java versions of what you posted:
public class Speaker {
private final String firstName;
private final String surname;
private final NameSource nameSource;
public Speaker(String firstName, String surname, NameSource nameSource) {
this.firstName = firstName;
this.surname = surname;
this.nameSource = nameSource;
}
public String introduce() {
String name = nameSource.createName(firstName, surname);
return String.format("Hi, my name is %s", name);
}
}
public interface NameSource {
String createName(String firstName, String surname);
}
public class Formal implements NameSource {
#Override
public String createName(String firstName, String surname) {
return String.format("%s %s", firstName, surname);
}
}
Then, a test which exercises all the useful features of the classes, without resorting to what you were originally asking for.
#RunWith(JMock.class)
public class ExampleTest {
private Mockery context = new JUnit4Mockery();
#Test
public void testFormalName() {
// I would separately test implementations of NameSource
Assert.assertEquals("Joe Bloggs", new Formal().createName("Joe", "Bloggs"));
}
#Test
public void testSpeaker() {
// I would then test only the important features of Speaker, namely
// that it passes the right values to the NameSource and uses the
// response correctly
final NameSource nameSource = context.mock(NameSource.class);
final String firstName = "Foo";
final String lastName = "Bar";
final String response = "Blah";
context.checking(new Expectations() {
{
// We expect one invocation with the correct params
oneOf(nameSource).createName(firstName, lastName);
// We don't care what it returns, we just need to know it
will(returnValue(response));
}
});
Assert.assertEquals(String.format("Hi, my name is %s", response),
new Speaker(firstName, lastName, nameSource).introduce());
}
}
JMock doesn't support your use case (or any other mocking framework I know of in java).
There's a little voice in my head that says that what you're trying to do is not ideal and that your unit test might be to complicated (maybe it's testing too much code/logic?). One of the problems I see, is that you don't know which values those mocks need to return and you're plugging something else, which might make each run irreproducible.

Categories

Resources