JUnit lambda expression - java

Good morning,
I need to make a test for a class which use the following method:
File[] files = directory.listFiles((dir, name) -> name.startsWith("FILE_500"+date));
To test this part of code I have the following code:
when(directory.listFiles((dir,name)->name.startsWith("FILE_500"))).thenReturn(files);
But IDE says "Unnecessary stubbings detected" because name.startsWith is never call on test.
How can I test this part of code?
Kind regards

Since you want to test the behavior of the listFiles method when it is passed a lambda expression as a parameter, you can create a mock object of the File class and set it up to return the expected array of files when the listFiles method is called with a lambda expression that matches the condition you want to test.
Please refer to the example test case using Mockito :
#Test
public void testListFiles() {
File[] expectedFiles = {new File("FILE_50020230215.txt"), new File("FILE_50020230215.csv")};
File directory = mock(File.class);
when(directory.listFiles(any())).thenReturn(expectedFiles);
File[] actualFiles = directory.listFiles((dir, name) -> name.startsWith("FILE_50020230215"));
assertEquals(expectedFiles.length, actualFiles.length);
for (int i = 0; i < expectedFiles.length; i++) {
assertEquals(expectedFiles[i], actualFiles[i]);
}
}

Related

How to create JUnit tests for different input files as separate cases?

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.

jUnit for file reader

I got a method that read from a txt file and populate a list with words that are exists in the file.
the method is calculate and return Most Repeated Word.
If I want to write a jUnit for that. how should I test the corectess of that method given the fact the file is changing frequentaly.
As #jaibalaji wrote, JuintTests should not depend on resources outside of the JVMs memory.
So the first step must be to make your code under test (cut) independent of the actual file.
I got a method that read from a txt file and populate a list with words that are exists in the file. the method is calculate and return Most Repeated Word.
In this sentences you mention 3 responsibilities:
reading a file
populating a list
find Most Repeated Word
You should split this method so that you ed up with smaller classes with the one responsibility each only.
class TextAnalyser{
private final WordListBulder wordListBulder; // converts String into List of words
private final WordCountAnalyser wordCountAnalyser;
public TextAnalyser(WordListBulder wordListBulder, WordCountAnalyser wordCountAnalyser){
this.wordListBulder = wordListBulder;
this.wordCountAnalyser = wordCountAnalyser;
}
public String findMostRepeatedWordIn(MyFileReader myFileReader){
String fileContent = myFileReader.readContent();
List<String> wordList = wordListBulder.crerateWordListFrom(fileContent);
return wordCountAnalyser.findMostRepeatedWordIn(wordList);
}
This code is too simple to fail and don't need to be UnitTested. Module- and/or Acceptance-Tests will show that this works.
Now the behavior to test is in the class WordCountAnalyser. And it has a simple t "fake" input which leads to a deterministic testable output.
The file should be a parameter of the method or an instance field of the class of this method.
In this way, you can unit test the method by providing a file which you master the data and you know how assert them.
For example with the parameter way :
public String findMostRepeatedWork(File file){
...
}
And so you could unit it easily :
#Test
public void findMostRepeatedWork(){
// fixture
File myTestFile = ...;
// action
new MyClassToTest.findMostRepeatedWork(myTestFile);
// assertion
...
}
Junit is not intended for any test that is taking resources(file, dB or network)

mockito, wanted but not invoked

I have a problem.
I create object with mockito. Then I do the verification of the method and when running the test, it gives me error of Wanted but not invoked. And that the service stays as ().
#Test
public void recordTest() throws IOException, URISyntaxException
{
URL resourceUrl = getClass().getResource(F1);
Path resourcePath = Paths.get(resourceUrl.toURI());
Object object = new Object ();
when(objectServiceMock.getObjectByNem((Nem) anyObject())).thenReturn(object);
Page<HorvarATPF> pageHorvar = new Page<HorvarATPF>();
when(horvarATPFServiceMock.getHorvarATPFs((FilterHorvarATPF) anyObject())).thenReturn(pageHorvar);
horvarATUtilService.record(resourcePath.toFile());
verify(objectServiceMock, times(1596)).getObjectByNem((Nem) anyObject());
}
test doesn´t run in line of verify, with Wanted buy not invoked.
The proble is
verify(objectServiceMock, times(1596)).getObjectByNem((Nem) anyObject())
Mockito expects that you call this method 1596 times.
But you declare that it calls just once.
when(objectServiceMock.getObjectByNem((Nem) anyObject()).
To fix test just put
verify(objectServiceMock).getObjectByNem((Nem) anyObject());
or
verify(objectServiceMock, times(1)).getObjectByNem((Nem) anyObject())
here is examples from mockito documentation Verifying exact number of invocations / at least x / never

How do I run the same JUnit test multiple times with different test data each time?

I am just getting started with unit testing. I did the junit tutorial from a pdf from the tutorial points website. So my question is, I want to test my shunting yard algorithm and my RPNEvaluator.
The constructors (and any other variables to help you out with the context) look like this:
ShuntingYard.java:
private ArrayList<String> tokens = new ArrayList<String>();
public ShuntingYard(ArrayList<String> tokens) {
this.tokens = tokens;
}
RPNEvaluator.java:
private Queue<String> polishExpression;
public RPNEvaluator(Queue<String> exp) {
polishExpression = exp;
}
ShuntingYard.java has a method called toRpn() which will take an ArrayList and return a Queue after some processing.
RPNEvaluator has a method called evaluate which will take a Queue type and return a double after some processing.
With Junit I am trying to write some unit tests and I wanted to know if this start was the best way to go about it:
package testSuite;
import static org.junit.Assert.fail;
import java.util.ArrayList;
import org.junit.Before;
import org.junit.Test;
public class ExpressionEvaluationTest {
/**
* Initialise the lists to be used
*/
#Before
public void beforeTest() {
ArrayList<String> exprOne = new ArrayList<String>();
exprOne.add("3");
exprOne.add("+");
exprOne.add("4");
exprOne.add("*");
exprOne.add("2");
exprOne.add("/");
exprOne.add("(");
exprOne.add("1");
exprOne.add("-");
exprOne.add("5");
exprOne.add(")");
exprOne.add("^");
exprOne.add("2");
exprOne.add("^");
exprOne.add("3");
ArrayList<String> exprTwo = new ArrayList<String>();
exprTwo.add("80");
exprTwo.add("+");
exprTwo.add("2");
ArrayList<String> exprThree = new ArrayList<String>();
exprThree.add("2");
exprThree.add("/");
exprThree.add("1");
exprThree.add("*");
exprThree.add("4");
ArrayList<String> exprFour = new ArrayList<String>();
exprFour.add("11");
exprFour.add("-");
exprFour.add("(");
exprFour.add("2");
exprFour.add("*");
exprFour.add("4");
exprFour.add(")");
ArrayList<String> exprFive = new ArrayList<String>();
exprFive.add("120");
exprFive.add("/");
exprFive.add("(");
exprFive.add("10");
exprFive.add("*");
exprFive.add("4");
exprFive.add(")");
ArrayList<String> exprSix = new ArrayList<String>();
exprSix.add("600");
exprSix.add("*");
exprSix.add("2");
exprSix.add("+");
exprSix.add("20");
exprSix.add("/");
exprSix.add("4");
exprSix.add("*");
exprSix.add("(");
exprSix.add("5");
exprSix.add("-");
exprSix.add("3");
exprSix.add(")");
}
#Test
public void test() {
}
}
I was going to put this in the before() method:
ShuntingYard sy = new ShuntingYard(/arraylist here/);
And then in the test, pass the lists to the algorithm. My question is that I think I am going the long way around it, would it be better to have a parameterised annotation and pass those lists as a list of parameters?
and a further question: if a test for any of the ArrayLists passes then I am sure I can execute a subsequent test to the RPNEvaluator evaluate method. I hope I haven't been ambiguous.
Help would be very much appreciated.
I would come at it a little differently. Instead of just creating several sets of test data and calling the same test each time break it up in to something meaningful. Instead of writing one test called test() write several separate tests for each aspect of ShuntingYard. For example:
#Test public void
itDoesntDivideByZero()
{
ArrayList<String> divideByZeroExpression = Arrays.asList("5", "0", "/");
// Add code to call your method with this data here
// Add code to verify your results here
}
#Test public void
itCanAdd()
{
ArrayList<String> simpleAdditionExpression = Arrays.asList("1", "2", "+");
// Add code to call your method with this data here
// Add code to verify your results here
}
and so on. This will make your JUnit output much easier to read. When there's a failure you know that it failed while trying to add, or it failed while trying to evaluate an expression that would cause a divide by zero, etc. Doing it the way you have it in the original you'd only know that it failed in the test() method.
Each of the tests here does 3 things:
Arranges the test data
Performs some action with that data
Asserts that the results of the action are as expected
This Arrange, Assert, Act idiom is very common in automated testing. You may also see it called Given, When, Then as in, "Given these conditions, when I call this method, then I should get this result".
Try to get out of the mindset of writing one test to test an entire class or method. Write a test to test one part of a method. Consider this class:
public class Adder {
public int addOneTo(int someNumber) {
return someNumber + 1;
}
}
You might end up with a test suite that looks like:
#Test public void
itAddsOne()
{
int numberToAddTo = 1;
int result = new Adder().addOneTo(numberToAddTo);
assertEquals("One plus one is two", 2, result);
}
#Test(expected="NullPointerException.class") public void
itChokesOnNulls()
{
new Adder().addOneTo((Integer)null);
}
#Test public void
itDoesntOverflow()
{
int result = new Adder().addOneTo(Integer.MAX_VALUE);
// do whatever here to make sure it worked correctly
}
And so on.
The advise from Mike B is very good, try to separate your test thinking in one test per behavior/functionality.
For make your test more readable i probably write a static constructor for the class ShuntingYard that receives a string, then you can write:
ShuntingYard addition = ShuntingYard.createFromExpresion("2+2");
assertThat(addition.getRpn().evaluate(), is(4));
you can refactor a little more and ends with something like that:
assertThat(evaluate("2+2"), is(4))
That is easy to understand an and easy to read, and in addition write more test with diferent scenarios its one-line of code.
Other option its to write parametrized test, one example: http://www.mkyong.com/unittest/junit-4-tutorial-6-parameterized-test/, but in my opinion are really ugly. This test are normally called "data driven test" and are used when you want to test the same code with different input values.
For this data-driven test a much better option its to use something like spock, a groovy framework for testing that allows you to write incredible semantic test, and of course you can use for testing java code, check this out: http://docs.spockframework.org/en/latest/data_driven_testing.html

What should be the description for this method?

OK this method reads a dirctor, verify the file paths are ok and then pass each file to a method and updates a Map object.
But how can i explain this for java doc. I want to create a java doc and how should i explain this method for the documentation purpose. Please tell me, if you can help me with this example, i can work for my whole project. thank you:
private void chckDir() {
File[] files = Dir.listFiles();
if (files == null) {
System.out.println("Error");
break;
}
for (int i = 0; i < files.length; i++) {
File file = new File(files[i].getAbsoluteFile().toString());
Map = getMap(file);
}
}
Your method doesn't do what you said In your first sentence (doesn't verify file paths, and throws the result of getMap() away), but there's nothing wrong with putting that kind of sentence im the Javadoc.
There are some issues with your code:
The break statement will give a compilation error, I think. It should be a return.
It is bad style to name a field with a capital letter as the first character. If Dir and Map are field names, they should be dir and map respectively.
The statement Map = getMap(file); is going to repeatedly replace the Map field, and when you exit the loop, the field will refer to the object returned by the last getmap call. This is probably wrong.
Finally, change the file declaration as follows. (There is no need to create a new File object ... because getAbsoluteFile() reurns a File)
File file = files[i].getAbsoluteFile();

Categories