Junit test not working for sumoverarray method Java - java

I am trying to run a test for my sumoverarray method but I keep getting a failure saying AssertionError. Here's my method.
public class SumOverArray {
public static int IterateAndSum(int[] arr) {
int sum=0;
for (int i:arr) {
sum=sum+i;
}
return sum;
}
}
Here is my junit test
#Test
public void test3() {
int[] arr = { 1, 2, 3 };
assertNotEquals(0, SumOverArray.IterateAndSum(arr));
try {
SumOverArray.IterateAndSum(null);
assertTrue(true);
} catch (NullPointerException e) {
fail();
}
int [] arr2 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
assertEquals(78, SumOverArray.IterateAndSum(arr2));
int[] arr3 = { -1, -2, -3, -4, -5, -6, -7, -8, -9 };
assertEquals(-45, SumOverArray.IterateAndSum(arr3));
int[] arr4 = { 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80 };
assertEquals(1095, SumOverArray.IterateAndSum(arr4));
}

The behaviour is expected. Looking at the second part of the test method:
try {
SumOverArray.IterateAndSum(null);
assertTrue(true);
} catch (NullPointerException e) {
fail();
}
We call SumOverArray.IterateAndSum with null and expect no NullPointerException to be thrown. But looking at the implementation, we do not perform a null-check in method SumOverArray.IterateAndSum and thus try to iterate over null. This, ultimately, leads to a NullPointerException to be thrown. The catch-block in the test is entered and the test fails.
All other tests would pass, if this test would pass.
Ideone demo
If we, however, want to assert that a NullPointerException is thrown when null is passed as parameter, then we can use Assertions.assertThrows(...):
final NullPointerException exception = assertThrows(
NullPointerException.class,
() -> SumOverArray.IterateAndSum(null));
// validate exception here if necessary
Some remarks on the code:
Method names in Java should always start with a lowercase letter (IterateAndSum -> iterateAndSum)
A test should test one thing and one thing only. Thus, the one test method above should be written as four tests.
The last three tests are redundant, one of them is sufficient.
The explicit fail() on an exception is superfluous and can be omitted.
Semantically, the first test is also covered by the last three tests. Thus this test is also redundant.
I would suggest to define a value to return if null is passed as argument, 0 seems sensible.
This leaves us with the following two tests:
#Test
#DisplayName("should return 0 if null is passed as argument")
public void shouldReturnZerofNullIsPassedAsParameter() {
// GIVEN: nothing
// WHEN
final int actual = SumOverArray.iterateAndSum(null);
// THEN
assertEquals(0, actual);
}
// Alternative test, if we want to assure that a NPE is thrown if null is passed
#Test
#DisplayName("should throw NPE if null is passed as argument")
public void shouldThrowNullPointerExceptionIfNullIsPassedAsParameter() {
// GIVEN: nothing
// WHEN & THEN
assertThrows(
NullPointerException.class,
() -> SumOverArray.iterateAndSum(null));
}
#Test
#DisplayName("should return 78 if 1, 2 , ... , 12 are summed")
void shouldReturnCorrectResult() {
// GIVEN
final int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
// WHEN
final int actual = SumOverArray.iterateAndSum(arr);
// THEN
assertEquals(78, actual);
}

Related

is this a good way to call Junit assertions in a common method?

I have written tests which call a method to find the missing number in a given 1 to n array. The test code is as follows:
public class MissingNumberInArrayTest {
private int arrElements;
private int[] arr;
#Test
public void mustReturnMissingNumberCase1() {
// Given
arrElements = 5;
arr = new int[]{1, 2, 3, 4};
// When & Then
callAssertion(arr, arrElements, 5);
}
#Test
public void mustReturnMissingNumberCase2() {
// Given
arrElements = 5;
arr = new int[]{2, 3, 4, 5};
// When & Then
callAssertion(arr, arrElements, 1);
}
public void callAssertion(int[] arr, int arrElements, int expected) {
// When
int missingNumber = MissingNumberInArray.findMissingNumber(arr, arrElements);
// Then
Assertions.assertEquals(expected, missingNumber);
}
}
As you can see, I have multiple cases to test and have used the assertion in common method which takes input and asserts the data. Is this a good way of writing tests?
This question doesn't have an exact answer (IMO), so it will probably be deleted soon.
I wouldn't do it for simple cases like your example but if it makes your life easier, I don't see anything wrong with it. You could rename the method as assertMissingNumber and it wouldn't be that much different than usual (although the method you really want to test is in the assertion call).
I think your specific example is perfect for parameterized tests, though.
This is what it would look like with Junit 4:
#RunWith( Parameterized.class )
public class MissingNumberInArrayTest {
#Parameterized.Parameters
public static Collection<Object[]> data() {
return Arrays.asList( new Object[][] {
{ 5, new int[]{1, 2, 3, 4}, 5},
{ 5, new int[]{2, 3, 4, 5}, 1}
});
}
#Parameterized.Parameter(0)
public int arrElements;
#Parameterized.Parameter(1)
public int[] arr;
#Parameterized.Parameter(2)
public int expected;
#Test
public void mustReturnMissingNumberCase() {
// When
int missingNumber = MissingNumberInArray.findMissingNumber(arr, arrElements);
// Then
assertEquals( expected, missingNumber);
}
}
You can check on the JUnit documentation for examples with JUnit 5

Passing int array in ParameterizedTest in java

I am trying to pass in an array for testing a certain algorithm, but the arrays seem to not be passed correctly or at all. I manually tested the algorithm so I know it works as it's supposed to. How can I pass arrays in for testing in JUnit 5?
#ParameterizedTest
#CsvSource(value = {"[13,14,65,456,31,83],[1331,65456]"})
public void palindromeCombos(int[] input, int[] expected){
Palindrome pal = new Palindrome();
List<Integer> actual = pal.allPalindromes(input);
int[] result = new int[actual.size()];
for(int i = 0; i < actual.size(); i++){
result[i] = actual.get(i);
}
Assertions.assertArrayEquals(expected, result);
}
Pablo's Answer is correct, of course, but personally I'm not a fan of parsing strings if I don't absolutely have to. Another approach could be to use a MethodSource instead, and explicitly provide the arguments you need:
public static Stream<Arguments> palindromeCombos() {
return Stream.of(
Arguments.of(new int[]{13, 14, 65, 456, 31, 83}, new int[]{1331, 65456}));
}
#ParameterizedTest
#MethodSource
public void palindromeCombos(int[] input, int[] expected) {
// Test logic...
}
Since there is not implicit conversion for arrays, you can use explicit conversion, first you need to declare you converter class:
class IntArrayConverter implements ArgumentConverter {
#Override
public Object convert(Object source, ParameterContext context)
throws ArgumentConversionException {
if (!(source instanceof String)) {
throw new IllegalArgumentException(
"The argument should be a string: " + source);
}
try {
return Arrays.stream(((String) source).split(",")).mapToInt(Integer::parseInt).toArray();
} catch (Exception e) {
e.printStackTrace();
throw new IllegalArgumentException("Failed to convert", e);
}
}
}
Then you can use it in your test:
#ParameterizedTest
#CsvSource(value = {
"13,14,65,456,31,83;1331,65456",
"1,2,3,4,5,6;10,20"}, delimiterString = ";")
public void palindromeCombos(#ConvertWith(IntArrayConverter.class) int[] input,
#ConvertWith(IntArrayConverter.class) int[] expected) {
System.out.println(Arrays.toString(input));
System.out.println(Arrays.toString(expected));
}
Notice that I removed the [] from the CsvSource and changed the delimiter to ;, so the arrays are expressed by a list of integers separated by comma.
If you want you can keep the format you had and handle it in the converter class.
For those two examples the output is:
[13, 14, 65, 456, 31, 83]
[1331, 65456]
[1, 2, 3, 4, 5, 6]
[10, 20]
If you need further information you can check this post: https://www.baeldung.com/parameterized-tests-junit-5

Beginner Java project: what is wrong with my Array?

I have just started learning Java as part of my university course and am having a problem with y first project. I am just starting to create a project that basically sorts coins. I am trying to make a method called printCoinList() that prints the contents of a coin list, indicating what denominations are currently in circulation (i.e "The current coin denominations are in circulation: 200,100,50,20,10), in pennies.
So far I have declared my instance fields, created a parameter and attempted to make this method. My only issue is when i try and test it in the main() method it seems to have a problem with me using an array as the coinList parameter. This is what I have so far:
public class CoinSorter {
//Instance Fields
String currency;
int minCoinIn;
int maxCoinIn;
int[] coinList;
//constructor
public CoinSorter(String Currency, int minValueToExchange, int maxValueToExchange, int[] initialCoinList) {
currency=Currency;
minCoinIn=minValueToExchange;
maxCoinIn = maxValueToExchange;
coinList= initialCoinList;
}
public void printCoinList() {
System.out.println("The current coin denominations are in circulation"
+ coinList);
}
public static void main(String[] args) {
//An example
CoinSorter exampleOne = new CoinSorter("pounds", 0, 10000, {10,20,50,100,200});
The only problems seems to be in exampleOne as when I take this out the rest of the code seems to run fine.
The error message is:
Exception in thread "main" java.lang.Error: Unresolved compilation problems:
The constructor CoinSorter(String, int, int, int, int, int, int, int) is undefined
Syntax error on token "{", delete this token
Syntax error on token "}", delete this token
So does anyone know what I am doing wrong?
This is because an array initializer may only be specified at declaration site or as part of an array creation expression. (JLS ยง 10.6)
Below is an array initializer at declaration site.
int[] array = { 2, 3, 5, 7, 11 };
This is short for
int[] array = new int[] { 2, 3, 5, 7, 11 };
However, it may not be used as 'array literal', unlike a string literal. That means that you must write out the array creation expression:
new CoinSorter("pounds", 0, 10000, new int[] { 10, 20, 50, 100, 200 });
Arrays in java can be declared/initialized using one of the following ways.
int[] myIntArray = {10,20,50,100,200};
int[] myIntArray = new int[]{10,20,50,100,200};
replace CoinSorter exampleOne = new CoinSorter("pounds", 0, 10000, {10,20,50,100,200});
with
CoinSorter exampleOne = new CoinSorter("pounds", 0, 10000, myIntArray );
OR
CoinSorter exampleOne = new CoinSorter("pounds", 0, 10000, new int[]{10,20,50,100,200});
Firt of all , in java , you need to specify the type of your Array :
CoinSorter exampleOne = new CoinSorter("pounds", 0, 10000, new int[]{10,20,50,100,200});
Then your "printCoinList" method will not work as excepted , this should print :
The current coin denominations are in circulation [I#7852e922
Your final code should be :
import java.util.Arrays;
public class CoinSorter {
//Instance Fields
String currency;
int minCoinIn;
int maxCoinIn;
int[] coinList;
//constructor
public CoinSorter(String Currency, int minValueToExchange, int maxValueToExchange, int[] initialCoinList) {
currency=Currency;
minCoinIn=minValueToExchange;
maxCoinIn = maxValueToExchange;
coinList= initialCoinList;
}
public void printCoinList() {
System.out.println("The current coin denominations are in circulation : "
+ Arrays.toString(coinList));
}
public static void main(String[] args) {
//An example
CoinSorter exampleOne = new CoinSorter("pounds", 0, 10000, new int[]{10,20,50,100,200});
exampleOne.printCoinList();
}
}
Result :
The current coin denominations are in circulation : [10, 20, 50, 100, 200]
Good luck :) I hope I could access to you future exchange and buy and hold some crypto :D
before creating an object CoinSorter exampleOne = new CoinSorter("pounds", 0, 10000, {10,20,50,100,200}); declare and initialize an array int arr[]={10,20,50,100,200}and then pass it in the constructor rather than passing {10,20,50,100,200}
like this
int arr[]={10,20,50,100,200};
CoinSorter exampleOne = new CoinSorter("pounds", 0, 10000, arr);

Invoke a java method which accepts `<? super T>` type parameter from scala code?

I'm writing some scalafx code, which needs to invoke a method from java:
val txtEditor = new TextArea {
text = "markdown here"
}
txtEditor.text.addListener(new ChangeListener[String] {
override def stateChanged(e: ChangeEvent): Unit = ???
})
But it reports compilation error on the addListener parameter:
Type mismatch, expected: ChangeListener[_ >: String],
actual: ChangeListener with Object { def stateChange(e:ChangeEvent) Unit }
And the addListener which is a java method:
void addListener(ChangeListener<? super T> listener);
How to fix it?
FTR, to answer the question title.
scala> val is = (1 to 10).to[collection.mutable.LinkedList].asJava
warning: there were 2 deprecation warning(s); re-run with -deprecation for details
is: java.util.List[Int] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
scala> is sort (new java.util.Comparator[Int] { def compare(a: Int, b: Int) = b - a })
scala> is
res13: java.util.List[Int] = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]

Why is my DataPoints method being called multiple times?

This test class:
#RunWith(Theories.class)
public class TheoriesConfusion
{
#DataPoints
public static int[] ints()
{
System.out.println("Generator called");
return new int[]{1, 2, 3, 4, 5};
}
#Theory
public void twoArgTest(int x, int y)
{
assertTrue(x < y || x >= y);
}
}
Prints the following output:
Generator called
Generator called
Generator called
Generator called
Generator called
Generator called
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.137 sec
This is quite counterintuitive, as I expect the data-generating function to be called only once. This has implications when creating random data, or any case where the data-generating method returns different results on each call, so I'd like to understand it.
After some experimentation, I've found that testing an array of length n against a Theory with c args, the generate function is called x times, where x = n^c + n^(c-1) + ... + n^0.
The source is a little difficult to comprehend, but my assumption is that it works something like this (pseudocode):
for firstArg in generateArgs():
for secondArg in generateArgs():
for thirdArg in generateArgs():
testTheory(firstArg, secondArg, thirdArg)
Which makes some sense, basically it's just not caching the results of the method, so if you want the method to be called just once, you have to annotate a static field, like:
#DataPoints
public static int[] ints = ints();
public static int[] ints()
{
System.out.println("Generator called");
return new int[]{1, 2, 3, 4, 5};
}

Categories