JUnit5: make multiple tests operate on the same object - java

I want to set up my JUnit5 tests to all operate on the same object. I read large files to use as test data, so I would prefer to read it once and utilize that same data for the rest of the tests.
I've created the following as a simple example where I try to achieve this using a static object ("list") (does not work):
import java.util.List;
import java.util.ArrayList;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
class ExampleTest {
// Single list object to be modified and accessed by the tests
private static List<String> list = new ArrayList<String>();
#BeforeAll
static void setUpBeforeClass() throws Exception {
// None
}
#Test
final void addFoo() {
list.add("foo");
}
#Test
final void addBar() {
list.add("bar");
}
#Test
final void printList() {
System.out.println(list.toString());
assert(list.toString().equals("[foo, bar]"));
}
}
The result of this is a failure of printList() where the list is empty instead of containing [foo, bar].
I have been able to make this work is by moving the methods that add data into the #BeforeAll:
private static List<String> list;
#BeforeAll
static void setUpBeforeClass() throws Exception {
list = new ArrayList<String>();
list.add("foo");
list.add("bar");
}
But having the data importing methods as tests separate from #BeforeAll would be preferred.
#TestInstance(TestInstance.Lifecycle.PER_CLASS) did not work either.

Use #FixMethodOrder annotation.
Refer to this article for example : https://www.mkyong.com/unittest/junit-run-test-in-a-particular-order/

The issue was with the JUnit method ordering (as noted by Abhijay). Utilizing #TestMethodOrder as described in the JUnit5 documentation to appropriately order the tests gave the desired result:
import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.MethodOrderer;
#TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class ScratchTest {
private static List<String> list = new ArrayList<String>();
#BeforeAll
static void setUpBeforeClass() throws Exception {
// None
}
#Test
#Order(1)
final void addFoo() {
list.add("foo");
}
#Test
#Order(2)
final void addBar() {
list.add("bar");
}
#Test
#Order(3)
final void printList() {
System.out.println(list.toString());
System.out.println(list.toString().equals("[foo, bar]"));
assert(list.toString().equals("[foo, bar]"));
}
}

Related

Mokito/Java - Static Methods Mock

For example I have the following classes below:
public class TesteEstatico {
public static String teste(){
return "FOO";
}
}
And I have a class that uses her method:
public class UsaTesteEstatico {
public String metodoParaTeste1 (){
return TesteEstatico.teste() + " BAR ";
}
public String metodoParaTeste2 (){
return "FOO "+TesteEstatico.teste() + " BAR ";
}
}
Test class:
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
#ExtendWith(MockitoExtension.class) public class UsaTesteEstaticoTest {
#InjectMocks
UsaTesteEstatico usaTesteEstatico;
#Test
void teste1(){
Mockito.mockStatic(TesteEstatico.class);
Mockito.when(TesteEstatico.teste())
.thenReturn("BANANA");
String res = usaTesteEstatico.metodoParaTeste1();
System.out.println(res);
}
#Test
void teste2(){
Mockito.mockStatic(TesteEstatico.class);
Mockito.when(TesteEstatico.teste())
.thenReturn("LARANJA");
String res = usaTesteEstatico.metodoParaTeste2();
System.out.println(res);
}
}
Error I get when trying to run the tests:
org.mockito.exceptions.base.MockitoException:
For TesteEstatico, static mocking is already registered in the current thread
To create a new mock, the existing static mock registration must be deregistered
Versions of the libs that are in the project:
junit-jupiter 5.5.2
mockito-junit-jupiter 3.2.14
mockito-inline 3.2.14
Any idea how to solve this, i've tried a few things but nothing successful.
NOTE: I cannot change or add any new libraries as it is a restricted project.
You should use try-with-resources block in each of the tests to close the mockStatic.
public class UsaTesteEstaticoTest {
UsaTesteEstatico usaTesteEstatico = new UsaTesteEstatico();
#Test
void teste1(){
try (var ms = Mockito.mockStatic(TesteEstatico.class)) {
Mockito.when(TesteEstatico.teste()).thenReturn("BANANA");
String res = usaTesteEstatico.metodoParaTeste1();
System.out.println(res);
}
}
#Test
void teste2(){
try (var ms = Mockito.mockStatic(TesteEstatico.class)) {
Mockito.when(TesteEstatico.teste()).thenReturn("LARANJA");
String res = usaTesteEstatico.metodoParaTeste2();
System.out.println(res);
}
}
}
Note on mockStatic in #BeforeAll
Using #BeforeAll is a trap and bad advice.
You should strive for independent tests that don't affect each other.
This is not the case for mockStatic called in #BeforeAll, as stubbing from test methods outlive the test methods.
For example
// BAD CODE DONT USE
public class UsaTesteEstaticoTest {
UsaTesteEstatico usaTesteEstatico = new UsaTesteEstatico();
static MockedStatic<TesteEstatico> ms;
#BeforeAll
public static void init() {
ms = Mockito.mockStatic(TesteEstatico.class);
}
#AfterAll
public static void close() {
ms.close();
}
#Test
void teste1() {
Mockito.when(TesteEstatico.teste()).thenReturn("BANANA");
String res = usaTesteEstatico.metodoParaTeste1();
System.out.println(res);
}
#Test
void teste2() {
String res = usaTesteEstatico.metodoParaTeste2();
System.out.println(res);
}
}
teste2 prints:
FOO BANANA BAR if run after teste1
FOO null BAR if run separately
This is precisely what you want to avoid.
you need to use static block to mock it.
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
#ExtendWith(MockitoExtension.class)
public class UsaTesteEstaticoTest {
#InjectMocks
UsaTesteEstatico usaTesteEstatico;
#BeforeAll
public static void init(){
Mockito.mockStatic(TesteEstatico.class);
}
#Test
void teste1(){
Mockito.when(TesteEstatico.teste())
.thenReturn("BANANA");
String res = usaTesteEstatico.metodoParaTeste1();
System.out.println(res);
}
#Test
void teste2(){
Mockito.when(TesteEstatico.teste())
.thenReturn("LARANJA");
String res = usaTesteEstatico.metodoParaTeste2();
System.out.println(res);
}
}

sharing store data between extensions in JUNIT5

Is there anyway we can share data between different extensions in JUNIT 5 using store
Example
public class Extension1{
beforeAllCallback(){
getStore(GLOBAL).put(projectId,"112");
}
}
public class Extension2{
beforeTestExecutionCallback(){
System.out.println("projectId="+getStore(GLOBAL).get(projectId));
}
}
Yes, two extensions can share state via the Store as follows.
Note, however, that you may wish to store the shared state in the root context Store if you want the state to be accessible across test classes.
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.BeforeTestExecutionCallback;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
#ExtendWith({ Extension1.class, Extension2.class })
public class Tests {
#Test
void test() {
// executing this results in the following being printed to SYS_OUT.
// PROJECT_ID=112
}
}
class Extension1 implements BeforeAllCallback {
public static final String PROJECT_ID = Extension1.class.getName() + ".PROJECT_ID";
#Override
public void beforeAll(ExtensionContext context) throws Exception {
context.getStore(Namespace.GLOBAL).put(PROJECT_ID, "112");
}
}
class Extension2 implements BeforeTestExecutionCallback {
#Override
public void beforeTestExecution(ExtensionContext context) throws Exception {
System.out.println("PROJECT_ID=" + context.getStore(Namespace.GLOBAL).get(Extension1.PROJECT_ID));
}
}

iterative testing using junit

I have a bunch of test inputs that I would like to run and compare the output with expected:
#Test
void test () throws IOExeption {
for (File i : readDir()) {
File out = foo(i);
assertEquals(FileUtils.readLines(expected), FileUtils.readLines(out));
}
}
I would like to run the tests using JUnit. But if I do it like the above then JUnit will stop after encountering the first test failure. Is there a better way to do this other than making each file its own test case like below?
#Test
void test1 () throws IOExeption {
File i = readFile("1.txt");
File out = foo(i);
assertEquals(FileUtils.readLines(expected), FileUtils.readLines(out));
}
#Test
void test2 () throws IOExeption {
File i = readFile("2.txt");
File out = foo(i);
assertEquals(FileUtils.readLines(expected), FileUtils.readLines(out));
}
I think, that you could use Parameterized. This is standard feature of JUnit. Below you can see an example.
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.Arrays;
import java.util.Collection;
#RunWith(Parameterized.class)
public class Foo {
#Parameterized.Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][] { { "1.txt" }, { "2.txt" } });
}
#Parameterized.Parameter // first data value (0) is default
public /* NOT private */ String fileName;
#Test
public void test() {
File i = readFile(fileName);
File out = foo(i);
assertEquals(FileUtils.readLines(expected), FileUtils.readLines(out));
}
}
I have not found JUnit official documentation about this, but you can find more details e.g. in this tutorial: https://www.tutorialspoint.com/junit/junit_parameterized_test.htm

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;
}

Is it possible to use partial mocking for private static methods in PowerMock?

From the examples on the PowerMock homepage, I see the following example for partially mocking a private method with Mockito:
#RunWith(PowerMockRunner.class)
// We prepare PartialMockClass for test because it's final or we need to mock private or static methods
#PrepareForTest(PartialMockClass.class)
public class YourTestCase {
#Test
public void privatePartialMockingWithPowerMock() {
PartialMockClass classUnderTest = PowerMockito.spy(new PartialMockClass());
// use PowerMockito to set up your expectation
PowerMockito.doReturn(value).when(classUnderTest, "methodToMock", "parameter1");
// execute your test
classUnderTest.execute();
// Use PowerMockito.verify() to verify result
PowerMockito.verifyPrivate(classUnderTest, times(2)).invoke("methodToMock", "parameter1");
}
However, this approach does not seem to work when the private method we wish to mock is static. I wish to create a partial mock of the below class, with the readFile method mocked:
package org.rich.powermockexample;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.List;
import static com.google.common.io.Files.readLines;
public class DataProvider {
public static List<String> getData() {
List<String> data = null;
try {
data = readFile();
} catch (IOException e) {
e.printStackTrace();
}
return data;
}
private static List<String> readFile() throws IOException {
File file = new File("/some/path/to/file");
List<String> lines = readLines(file, Charset.forName("utf-8"));
return lines;
}
}
Please could someone let me know how this can be achieved?
After doing a bit more research, it seems that PowerMockito.spy() and PowerMockito.doReturn() are what is required here:
package com.richashworth.powermockexample;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.assertEquals;
#RunWith(PowerMockRunner.class)
#PrepareForTest({DataProvider.class})
public class ResultsWriterTest {
private static List<String> mockData = new ArrayList<String>();
private ResultsWriter resultsWriter;
#BeforeClass
public static void setUpOnce() {
final String firstLine = "Line 1";
final String secondLine = "Line 2";
mockData.add(firstLine);
mockData.add(secondLine);
}
#Before
public void setUp() {
resultsWriter = new ResultsWriter();
}
#Test
public void testGetDataAsString() throws Exception {
PowerMockito.spy(DataProvider.class);
PowerMockito.doReturn(mockData).when(DataProvider.class, "readFile");
final String expectedData = "Line 1\nLine 2\n";
final String returnedString = resultsWriter.getDataAsString();
assertEquals(expectedData, returnedString);
}
}
For further details and the complete code listing, check out my blog post here: https://richashworth.com/post/turbocharge-your-mocking-framework-with-powermock/
Test class:
#RunWith(PowerMockRunner.class)
#PrepareForTest(DataProvider.class)
public class DataProviderTest {
#Test
public void testGetDataWithMockedRead() throws Exception {
mockStaticPartial(DataProvider.class, "readFile");
Method[] methods = MemberMatcher.methods(DataProvider.class, "readFile");
expectPrivate(DataProvider.class, methods[0]).andReturn(Arrays.asList("ohai", "kthxbye"));
replay(DataProvider.class);
List<String> theData = DataProvider.getData();
assertEquals("ohai", theData.get(0));
assertEquals("kthxbye", theData.get(1));
}
}
Class being tested (basically yours):
public class DataProvider {
public static List<String> getData() {
try {
return readFile();
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
private static List<String> readFile() throws IOException {
File file = new File("/some/path/to/file");
return readLines(file, Charset.forName("utf-8"));
}
}
In general, only use static mocking for classes that are beyond your control (e.g. java.io.File). Since DataProvider and readFile are your own, refactor DataProvider into a proper class (i.e. make its methods non-static), pull out readFile into a helper object and then mock that. See this answer https://stackoverflow.com/a/8819339/116509.

Categories