0


I want to test addElement method:

public class MyClass {
    private List<Integer> ints = new ArrayList<>();

    public void addElement(int element) {
        ints.add(element);
    }
}

I need to test if my element was added. According to class isolation I can't use any of ArrayList methods to check it. In fact I should mock my arrayList. But if I mock it and change behavior of get() method to return some value I can't be sure if my element is in that list.

How to test it?

3
  • 1
    check size before / after? Commented May 28, 2015 at 18:45
  • 1
    I don't understand why you can't assertEquals(intsPreviousSize + 1, ints.size()) after you add it. What do you mean by class isolation? Commented May 28, 2015 at 18:46
  • The mock part is also unclear, if you use a mock for the list, you just have to "verify" add was called Commented May 28, 2015 at 18:48

4 Answers 4

3

assertEquals(intsPreviousSize + 1, ints.size()), and have a getter method for the ints ArrayList. If you can't have a getter, then you can use reflection, and if you can't do that then I don't think you can.

Sign up to request clarification or add additional context in comments.

Comments

1

What, at a mental rather than a code level, are you trying to test?

It sounds like you are trying to verify that MyClass.addElement(int) does in fact add an element.

What other public methods does MyClass have? If it has none, then it doesn't really matter if addElement(int) actually added the element, because there's no outward difference between the two possible cases.

I'm going to assume, then, that MyClass has some other methods which behave differently depending on the contents of ints, which you can use to determine if addElement(int) did what was expected.

For example, if there is a getter for ints, you could simply call it before and after addElement(int) and compare the List's contents at those two points.

Or, if there it a method which sums up the values in ints, you could call that and compare the value returned before and after calling addElement(int) and ensure the difference is equal to the int you added.

3 Comments

Exactly. The focus should be on the desired behaviour you want to test, if there are no other public methods then it doesn't matter if you remove all the code from inside addElement as the observable behaviour can't change. +1
It's also worth asking yourself if a method actually needs its own test case. If you're writing a unit test for a method as simple as the one in OP's question, you're doing useless work for work's own sake.
I doubt it is as simple as just adding and checking. What if he has if (element < 50) then add? There can be logic behind how he is adding it. I don't understand what other public methods have anything to do with this. He just wants to test that functionality.
0

I would recommend creating a subclass of MyClass, which has some type of public method to retrieve the ArrayList (or a specific element in the list). The ints object will also need to have its access level changed to protected if you want to access it from a subclass. If you wanted it a little tighter, you could use the default scope, and require your new class to be in the same package as MyClass. I have done this before, and would consider it a reasonable cost to be able to unit test your code.

This way the parent class will be tested, but you can use the sub class to retrieve the information from your test.

For example:

public class MyClass {
    protected List<Integer> ints = new ArrayList<>();
    ...
}

public class MyClassChild extends MyClass {
    public List<Integer> getInts() {
        return ints;
    }
}

// Test code
MyClassChild myClass = new MyClassChild();
myClass.addElement(42);
myclass.getInts().size() == 1;

If all else fails, you can fall back on reflection to retrieve the object, but that is more cumbersome (in my opinion).

5 Comments

While technically a correct method it is questionable. You would not want to bloat your code base with derived classes meant only for testing. Mockito and PowerMock frameworks already provide facilities for testing void methods.
Perhaps I should clarify - this class would not be included with the main code base (that would be a terrible idea), this would be in the corresponding package in your test folder, this will keep the test code out of production code.
If you are going to make it private to protected, then I feel you might as well just have a public getter
@BrandonLing I disagree. There are many levels of opening up access to a variable, and making something default or protected is still different from having a public getter. Yes, those two will make it easier to retrieve the variable, but not so much as a public getter.
@mnd Sure, of course there's a few use cases, but I would assume the large majority would fall under a public getter being fine, and avoiding all that trouble of creating a subclass etc.
0

Focus on the behaviour that you want to test. in what externally testable way does MyClass change after addElement is called? this should be the focus of your test.

Tests generally fall into two categories.

  • Testing state changes
  • Testing interactions

In this case it looks like you are testing state changes (although that's not 100% clear from your cut down example). When testing state changes you generally want to set things up, perform some action and then verify the state of your object has changed in the expected way. In these tests you generally do not need mocks (although you might need stubs to provide test data)

In this case you would add an element and then call some additional method to verify that the element has been added, like trying to get it, or verifying that the number of stored elements had increased. Without more details of what your object actually does its hard to guide you exactly.

the fact that you have a private array list inside your class is an implementation detail and should not be the focus of your test, otherwise if you decide to change the array list for something else in the future your tests will likely need updating.

When testing interactions you generally want to set things up, perform some action and then verify that the interactions that were expected took place. In these tests you might want to use mocks for the interactions you are testing.

For example you might want to check the interaction of your class with another class (like a logger or a database access class) is happening in the expected way.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.