Wrong results with Junit parameterized - java

I changed a junit test class to run with Parameterized to test two different implementations of the same interface. Here it is :
#RunWith(Parameterized.class)
public class Stack_Tests {
private Stack<String> stack;
public Stack_Tests(Stack<String> stack) {
this.stack = stack;
}
#Parameters
public static Collection<Object[]> parameters() {
// The two object to test
return Arrays.asList(new Object[][] { { new LinkedStack<String>() }, { new BoundedLinkedStack<String>(MAX_SIZE) } });
}
#Test
public void test() {
...
}
The results are wrong since I changed to Parameterized. Half of the tests fail (the same for the two objects), all of them worked before.
It works without Parameterized like this :
public class Stack_Tests {
private Stack<String> stack;
#Before
public void setUp() throws Exception {
stack = new LinkedStack<String>();
}
#Test
public void test() {
...
}
The complete test class here

As you suggested in the comments, try resetting the stack before every test, since previous tests change it.
You can create a new stack instance before every unit test:
#Before
public void setUp() throws Exception {
stack = stack.getClass().newInstance();
}
Though this has the side effect that your classes must have 0-argument constructors.
Note: If some of your stacks can not have 0-argument constructors, consider invoking the constructor with arguments as per this SO answer. This means that you must provide the constructor types list and its arguments list along with the stack object to the unit test class as parameters. Then you can do:
#Before
public void setUp() throws Exception {
stack = stack.getClass().getDeclaredConstructors(typesList).newInstance(argsList);
}

add :
#Before
public void setUp() throws Exception {
stack.clear();
}
the stack is shared for each test, and your tests modify the stack.

To get a consistent stack for all tests, an alternative approach is to clone the stack before modifying it in a particular test.
#Test public void testPush() {
Stack<String> myStack = (Stack<String>) stack.clone();
myStack.push("hello");
assertFalse(myStack.empty());
}
Thus, every test that modifies the stack should first clone it.
This is a little more cumbersome, but allows to provide more sophisticated stacks as parameters (e.g., ones with some elements to start with).

Related

Java MockedStatic method is still called

So I'm using MockedStatic<> to mock a static method but it seems like the item inside is still getting called? If this is the case, what's the point of mocking it? I have the following setup:
Object being tested:
public class ObjectBeingTested {
public void methodBeingTested() {
Object obj = ObjectInQuestion.getInstance(new Object(), "abc");
// do stuff with obj
}
}
The object with static method:
public class ObjectInQuestion {
public static ObjectInQuestion getInstance(Object obj, String blah) {
someLocalVar = new FileRequiredObject();
// we get NullPointerException here cuz in test env, no files found
}
private ObjectInQuestion() {
// private constructor to make people use getInstance
}
}
Test code:
public class MyTestClass {
MockedStatic<SomeClass> mySomeClass;
#Mock ObjectInQuestion mMockedObjectInQuestion;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
mySomeClass = mockStatic(SomeClass.class);
when(SomeClass.getInstance(any(), anyString()).thenReturn(mMockedObjectInQuestion);
}
#After
public void tearDown() {
mySomeClass.close();
}
}
My questions are the following:
Why calling ObjectInQuestion.getInstance() in the test class, it's totally fine but when it's being called from ObjectBeingTested, it runs the real construction?
I tried to use mockConstruction on FileRequiredObject, it still actually construct the object ... why?
You're using the wrong syntax for stubbing the static method. You want something like
mySomeClass.when(
()->SomeClass.getInstance(any(), anyString()))
.thenReturn(mMockedObjectInQuestion);
More information available here
Assuming MockedStatic<SomeClass> mySomeClass; is actually MockedStatic<ObjectInQuestion> mySomeClass;, I would try to simplify the setup using a classic try block.
In any case, sharing the actual test method might be able to shine some light. ;)

Mockito - Zero interactions with mock - Singleton

Preconditions
I have the following class (fictional, just for demonstrating the problem):
public class MySingleton {
private static MySingleton sMySingleton;
private static List<String> sItemList;
private MySingleton(List<String> list) {
sItemList = list;
}
public static MySingleton getInstance(List<String> list) {
if (sMySingleton == null) {
sMySingleton = new MySingleton(list);
}
return sMySingleton;
}
public void addItem(String item) {
sItemList.add(item);
}
public void removeItem(String item) {
sItemList.remove(item);
}
}
And an according test class:
public class MySingletonTest {
private MySingleton mInstance;
private List<String> mList;
#Before
public void setup() {
mList = mock(List.class);
mInstance = MySingleton.getInstance(mList);
}
#Test
public void testAddItem() throws Exception {
String item = "Add";
mInstance.addItem(item);
verify(mList, times(1)).add(item);
}
#Test
public void testRemoveItem() throws Exception {
String item = "Remove";
mInstance.removeItem(item);
verify(mList, times(1)).remove(item);
}
}
Problem
If I now execute the complete test class, Mockito tells me for the test testRemoveItem() that there were 0 interactions with the mock.
How is that possible?
Note:
Please do not start of a discussion about the sense singletons.
This question is about Mockito and why its not working.
JUnit creates a new test class instance for every single test, which Mockito populates with a new mock instance for every single test. However, your singleton only ever initializes itself once, meaning that mList == MySingleton.sItemList during the first test but mList != MySingleton.sItemList for every test after that.
In other words, the interaction is happening, but by the second test, you're checking the wrong mock.
Though I know you're not here to debate the merits of this type of singleton, bear in mind that you might have a hard time replacing the instance in tests if you do it this way. Instead, consider making the singleton's constructor available (only) to your tests, and keeping the List (or other state) within the instance. That way you can create a brand new "Singleton" for every individual test.

TestNG #Factory Priority

Is there a way to put a priority on a #Factory method? I've tried #AfterMethod, #AfterTest, and #AfterClass, all result in my factory method running immediately after my setup call with the #BeforeClass tag.
My code is similar to this:
#BeforeClass
public void setup() {
}
#Test()
public void method1() throws Exception {
}
#Test(dependsOnMethods = "method1")
public void method2() {
}
#Test(dependsOnMethods = "method2")
public void method3() throws Exception {
}
#Test(dependsOnMethods = "method3")
public void method4() throws Exception {
}
#Test(dependsOnMethods = "method4")
public void method5() throws Exception {
}
#AfterClass
#Factory
public Object[] factory() {
Object[] values = new Object[10];
for (int i = 0; i < values.length; i++) {
values[i] = new validationFactory(map.get(i).x, map.get(i).y);
}
return values;
}
What the code is doing is reaching out to an API, retrieving any requested data, slicing that data up into a map, and then passing that map of data into the factory method in order to validate it. The problem is that immediately after my setup method runs, the factory shoots off and validates an empty map. Is there any way to make the factory method wait until the data is ready?
The purpose of #Factory is to create tests dynamically. It doesn't make sense to run those tests after an #AfterClass method, so even if you could work around your problem by checking if the map was empty (so that factory() runs twice, but the loop - only once), any tests created by the factory would not be executed by the framework.
If what you need is to validate some data after all the tests have finished, put that validation in a method annotated with #AfterClass (without #Factory). You can use assertions there as in a regular test.
If for some reason you want to run the validation as separate tests and have to use a factory, there is a way to defer their execution until after the other tests, but they still have to be instantiated at the beginning. So it looks like you need to pass some object that would load the data when required instead of initializing the validation tests with map entries right away. A data provider may work, but here's a simpler example.
Add all the main tests to a group.
#Test(dependsOnMethods = "method1", groups = "Main")
public void method2() { }
Create a class or a method that will load the data when needed, it depends on how you populate the map. It has to be thread-safe because TestNG runs tests in parallel. A very simplistic implementation:
public class DataLoader {
// Location has data members X and Y
private Map<Integer, Location> locations;
public synchronized Location getLocation(int index) {
if (locations == null) {
locations = new HashMap<>();
// load the map
}
return locations.get(index);
}
}
Create a class to represent a validation test. Notice its only test depends on the main group.
public class ValidationTest {
private int index;
private DataLoader loader;
public ValidationTest(int index, DataLoader loader) {
this.number = number;
this.loader = loader;
}
#Test(dependsOnGroups = "Main")
public void validate() {
Location location = this.loader.getLocation(this.index);
// do whatever with location.x and location.y
}
}
Instantiate the validation tests. They will run after the main group has finished. Notice I have removed the #AfterClass annotation.
#Factory
public Object[] factory() {
DataLoader loader = new DataLoader();
Object[] validators = new Object[10];
for (int i = 0; i < validators.length; i++) {
validators[i] = new ValidationTest(i, loader);
}
return validators;
}
By the way, dependencies between test methods indicate poorly written tests, and should be avoided, at least for unit-tests. There are frameworks other than TestNG for testing complex scenarios.
A TestNG run has 2 distinct phases:
Creation of tests ;
Run of tests.
Then, you can expect to create some new tests during the run of tests.

The best way to test classes implementing the same interface

So, for example I have a few classes implementing the List<T> interface. How to test them - whether they implement the methods correctly?
Now I only see one way to do so:
public class MyListImplementationsTest {
private Collection<List<Integer>> listImplementations;
#BeforeClass
public static void setUp() throws Exception {
listImplementations = Arrays.asList(
new QuickList<Integer>(), new EfficientMemoryList<Integer>()
);
}
#Test
public void testIsEmptyAfterCreationEmptyList() {
// Use forEachList(handler) in order to not iterate
// the lists manually every time.
// May be there is no need to do so,
// because using <<for (item : items)>> instead of
// iterating using index prevents from OutOfBounds errors
forEachList(new OnEachListHandler<Integer>() {
#Override
public void onEach(List<Integer> list) {
assertTrue(list.isEmpty());
}
});
}
private <T> void forEachList(OnEachListHandler<T> handler) {
for (List<T> each : listImplementations) {
handler.onEach(each);
}
}
private static interface OnEachListHandler<T> {
void onEach(List<T> each);
}
}
But in my opinion it's complicated to iterate lists in every test.
Is there more elegant way to test classes implementing the same interface in JUnit4?
You can create a base test which can test anything of type List<T> plus an abstract method which creates such a list.
Then implement a test per list type which extends the base test. JUnit will run the test cases from the base class plus any that you define in the extension.
abstract class AbstractListTest<T> {
protected abstract List<T> createList();
#Test
public void testIsEmpty() {
List<T> list = createList();
assertTrue(list.isEmpty());
}
...more tests...
}
class QuickListTest extends AbstractListTest<QuickList> {
protected QuickList createList() {
return new QuickList();
}
}
JUnit won't run the abstract base class but it will see the inherited tests and run all of them. You can also add new tests to QuickListTest or override ones from the base class.
Basically, JUnit will take the class, find all public #Test methods from the whole inheritance tree and run them.
I will consider breaking up the tests for different list implementations into their respective test cases, so that they pass or fail independently.
Using your .isEmpty() as an example, if QuickList.isEmpty() and EfficientMemoryList.isEmpty() have different implementations i.e. different meaning for the concept of empty, then it makes sense for them to be tested independently. Currently, your testIsEmptyAfterCreationEmptyList will fail if 1 list implementation failed, but the others passed.
Otherwise, if QuickList.isEmpty() and EfficientMemoryList.isEmpty() share the same implementation, then you can consider moving the implementation to a common base class, and write tests for that base class.
Just because classes share the same interface, doesn't mean their tests need to be lumped and coupled.
Create a test each implementation separatelly: QuickListTest and EfficientMemoryListTest.
QuickListTest.java
public class QuickListTest extends ListBase {
#Test
public void shouldBeEmpty() throws Exception {
assertThatIsEmpty(new QuickList<Integer>());
}
}
BaseList.java
public abstract class ListBase {
protected void assertThatIsEmpty(QuickList<Integer> actual) {
assertThat(actual).isEmpty();
}
}

JUnit parameterized- create one instance for each parameter

I was annoyed to find in the Parameterized documentation that "when running a parameterized test class, instances are created for the cross-product of the test methods and the test data elements." This means that the constructor is run once for every single test, instead of before running all of the tests. I have an expensive operation (1-5 seconds) that I put in the constructor, and now the operation is repeated way too many times, slowing the whole test suite needlessly. The operation is only needed once to set the state for all of the tests. How can I run several tests with one instance of a parameterized test?
I would move the expensive operation to a #BeforeClass method, which should execute just once for the entire parameterized test.
A silly example is shown below:
#RunWith(Parameterized.class)
public class QuickTest {
private static Object expensiveObject;
private final int value;
#BeforeClass
public static void before() {
System.out.println("Before class!");
expensiveObject = new String("Just joking!");
}
#Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][] { { 1 }, { 2 } });
}
public QuickTest(int value) {
this.value = value;
}
#Test
public void test() {
System.out.println(String.format("Ran test #%d.", value));
System.out.println(expensiveObject);
}
}
Will print:
Before class!
Ran test #1.
Just joking!
Ran test #2.
Just joking!

Categories

Resources