Verifying sequence of private method calls in unit testing - java

I have the following class:
class MyClass {
public void doIt() {
methodOne();
methodTwo();
methodThree();
}
private void methodOne() {
// ...
}
// rest of methods similar...
}
My intention is to verify that when i invoke doIt(), methods metodOne(), methodTwo() and methodThree() will be invoked, in that order.
I'm using mockito for mocking. Does anyone knows how i can test this scenario?

Hate to be the person but: simply don't test this. Test the output, side effects, results - not the implementation.
If you really want to ensure the correct order, extract these methods into separate class(es) and mock them.

As long as your private methods are ... well ... private, don't test them. They are implementation details. They could be refactored without changing the contract of your class. Test the correct outcome of your public methods.

Related

Writing Unit Tests for inherited classes in Java

Consider the following simple class hierarchy in Java
class Foo {
protected void someMethod(Bar bar) {
...
}
protected void someOtherMethod(Baz baz) {
...
}
}
class EnhancedFoo extends Foo {
#Override
protected void someMethod(Bar bar) {
...
}
}
I now start writing JUnit unit tests for these two classes. Since the contracts for the method someMethod are same for both the classes, I need basically exactly the same test methods (concerning the someMethod method) for both the classes, which leads to code duplication. Doing this for a much richer class hierarchy with multiple overwritten methods, it just feels like inheritance is bad for testability.
Also, even though the method someOtherMethod is not overridden in ExtendedFoo, I need to include the pertaining tests for ExtendedFoo because that is still the contract and this extended class and unit tests should test this.
Is there some other way of organizing hierarchies in Java that is better for testability? Is there some JUnit construct that would help alleviate this problem?
One approach we used when we had a very similar scenario was to also reuse the est classes:
class FooTest {
#Test
public void testSomeMethodBar() {
...
}
#Test
public void void someOtherMethodBaz(Baz baz) {
...
}
}
And extend it for subclass tests:
class EnhancedFooTest extends FooTest {
#Test
public void testSomeMethodBar() {
...
}
}
JUnit will run this specific overridden test method, and also the other default tests in FooTest. And that eliminates unnecessary duplication.
Where appropriate, some test classes are even declared abstract, and are extended by concrete test classes (tests for concrete classes).
As I mentioned in my comments I think the tests should be decoupled from the implementation and be "use-case-driven". It could look like that:
interface Foo {
public void doSomething(...);
}
class DefaultFoo implements Foo { ... }
class EnhancedFoo extends DefaultFoo { ... }
class MyUseCaseTest {
private Foo foo = new DefaultFoo(...);
#Test
public void someRequirement() { ... }
}
class AnotherUseCaseTest {
private Foo foo = new EnhancedFoo(...);
#Test
public void differentRequirement() { ... }
}
The best would be to get rid of inheritance whatsoever, but it's a different topic...
Quoting from your question and comments ,
As far as I understand, unit tests assume classes and their methods to
be black boxes and test their contracts.
And
Since the contracts for the method someMethod are same for both the
classes, I need basically exactly the same test methods (concerning
the someMethod method) for both the classes, which leads to code
duplication.
Both are wrong assumptions in the context of generic unit test concepts and might be correct assumptions in the very narrow context of TDD. You haven't tagged your question for TDD so I am just guessing that and TDD is all about what is acceptable & not necessarily very robust from code perspective.
TDD never stops a developer to write more comprehensive unit tests that satisfy him/her and not only contract.
You have to understand that unit tests are developer tools to assure for method accuracy and it doesn't assume methods as black boxes - it is supposed to test contract as well as implementation details ( code coverage ) .
A Developer shouldn't write unit tests blindly like for trivial methods ( like setter / getter methods ) .
When you go in detail for code coverage , you will find that you will have to write multiple test methods for a target method covering all the scenarios.
If implementation of below method is not changed in class - EnhancedFoo , why write unit tests for it? It should be assumed that parent class tests would be covering it.
protected void someMethod(Bar bar) {
...
}
You write unit tests for methods that you change or add and shouldn't be worried about inheritance hierarchy.
I am simply trying to emphasize the importance of word unit :)

How to write unit tests for method which calls other methods?

This is a really bad sample of code. Sorry about that.
I want to write a unit test for myMethod(). This only calls other methods and return String str1. I don't see there is any need of testing this code.
public class MyClass{
private String str1;
private String str2;
private void m1(){..}
private String m2(){
// do something
return someString;
}
public String myMethod(String s1){
str2 = s1;
m1();
str1 = m2();
return str1;
}
}
There are various ways to write unit tests.
A) You observe behavior. You create an object of your class under test, then you call methods; and then you assertThat on the values that are returned.
B) When your object uses other objects, then you might have to turn to mocking frameworks, for example to verify that you see the expected method calls on those objects.
In your case, it really depends on what m1/m2 are doing. As said - the best unit tests are those that only check the "observable" behavior of your code under test. Like those examples:
#Test(expected=NullPointerException.class)
public void testMyMethodWithNull() {
new MyClass().myMethod(null);
}
The above would check that when calling your method with null ... a NPE is thrown.
#Test
public void testMyMethodWithEmptyString() {
MyClass underTest = new MyClass();
assertThat(underTest.myMethod(""), is("some expected string for empty input"));
}
That one does some different checking for EMPTY input.
And so you work your way through all inputs that make sense. Of course, the idea here is that all possible behavior of your class under test can be checked this way. If there are others that come into play, you have to take them into consideration of course. But ideally, that should not be the case: you should design all your code so that it can be fully tested as easily as possible; and ideally without the need to write anything else but such kind of tests.
I completely agree with GhostCat:
[…] the best unit tests are those that only check the "observable" behavior of your code under test.
Therefore, only test the public contract of your class under test (CUT).
However, there're rare situations in which you may need to test private methods, e.g. if you're working with legacy code. One way to do this is with PowerMockito:
PowerMockito.verifyPrivate(cut).invoke("m1");
Where cut is an instance of your CUT – MyClass.
Checkout these questions for further opinions and references:
Should I test private methods or only public ones?
How do I test a class that has private methods, fields or inner classes?
Making a private method public to unit test it...good idea?
"I don't see there is any need of testing this [private method]."
Yes. That's right.
A method that is private doesn't need any direct testing. Of course, private methods should be covered, but since they are private and NOT a part of your exposed API, they don't need to be tested as directly as public methods.
This book--JUnit in Action: Second Edition--outlines many strategies for using JUnit effectively. Implementing TDD is one way to make sure that your class's non-public functionality is well-covered by your tests. That is, you write your unit tests first, then you implement your class to pass those tests. In this way, you only write functionality that you need, as defined by your tests.

Mocking a non-abstract method of an abstract class

I am trying to unit-test a class that extends an abstract base class.
Here are the "similar classes" for illustration purposes:
public abstract class MyAbstractBaseClass {
#Autowired
private WaterFilter waterFilter;
protected List<String> filterComponents(List<String> allComponents) {
return waterFilter.filter(allComponents);
}
}
public class MyDerivedClass extends MyAbstractBaseClass {
public List<String> filterWater(List<String> allWaterComponents) {
List<String> filteredComponents = this.filterComponents(allWaterComponents); //calls abstract class's filterComponets()
filteredComponents.add("something-else");
return filteredComponents;
}
}
Here is the unit test I am trying:
#RunWith(EasyMockRunner.class)
public class MyDerivedClassTest {
#TestSubject
private MyDerivedClassTest SUT;
#Before
public void setup() {
SUT = new MyDerivedClassTest();
}
#Test
public void test filterWater_HappyCase() {
//I want to mock my abstract class's filterComponents() method
//I am trying this:
EasyMock.expect(SUT.filterComponents(getDummyComponents())).andReturn(getSomeComponents());
//What to replay here?
//EasyMock.replay(...)
List<String> actualResult = SUT.filterWater(getDummyComponents());
//assert something
//What to verify?
//EasyMock.verify(...)
}
}
When I run this test, I get
java.lang.NullPointerException
in MyAbstractBaseClass.filter(allComponents)
I understand that the autowired "waterFilter" is not getting initialized. But then, I just want to mock the "non-abstract" method of the abstract class in my unit test.
How should I go about this using EasyMock? Also, I don't know what to replay() and verify().
When you write an unit test, you test a object (generally, a method of it) and you may mock a object (generally, a method of it).
However, you should not unit test and mock the same object because in a some way, it seems not very natural : if you test a method of a class, the behavior of the tested class should stay as natural as possible and not fake its own methods.
Otherwise, we can wonder if the quality of the unit test is good.
Why ? Because it doesn't reflect the real behavior of the class that we would have at the runtime, but just some part of its behavior.
In a unit test, isolation is researched but behind it, the idea is to isolate your under test class only from the other classes and not an isolation of its own behavior.
Of course, you can try to mock a no-abstract method in the abstract class of your under tested class but the design and the quality of your test may become less good.
In your case, I imagine two reasons to mock the no-abstract method in the abstract class :
the waterFilter field dependency annoys you because it is not valued, so an exception (NullPointerException) is raised during the test.
You really want to mock the no abstract method in the abstract class because you have already unitary tested this method and you don't want to duplicate this test.
1) If your the problem is the waterFilter field dependency.
you should mock the waterFilter field. To mock a field, it must be accessible and modifiable. In your case, it's not straight because the field is private.
So, you have two ways to access to it to be able to mock it :
change your design to give the possibility to set the field from a public method or in the constructor of MyDerivedClass.
use reflection to set the field (use an API or do it yourself because it's not hard).
You don't need to do verify operations with EasyMock. Just mock the result returned by waterFilter.filter(allComponents) such as :
waterFilterMock.filter(mockedComponents)
In this way, the mock returns the value you have chosen and in your JUnit assertion, you are able to do the correct assertion for your method under test.
Just for information, you could use Mockito instead of EasyMock. It's more flexible and it offers more readable operations.
For example, you could do it with Mockito :
Mockito.when(waterFilterMock.filter()).thenReturn(mockedComponents);
As you can see, it is more readable.
2) If you problem is that you really want to mock the no-abstract method in the abstract class because you have already unitary tested it
You should modify your design and use composition instead of inheritance. You would have not MyAbstractBaseClass any longer but simply a dependency between two classes (the one has a field of the other). In this way, you could mock the filterComponents() method in a natural way.
Expectations has to be set on mocked resources.
In your case i think you should inject a mocked instance of WaterFilter.
And your expectation,replay and verify should be set on waterFilter object instance.
You can refer to the example provided in given below link.
http://www.tutorialspoint.com/easymock/easymock_junit_integration.htm

Detecting a call to a Java API method from source code

Suppose that I want to write a unit test for a method or class that makes sure that the source code of that method does not call a certain Java API method (in this case, Arrays.sort). Is this even possible? The reason for which I want this is because I want to come up with automatic tests that detect if Arrays.sort has been called from anywhere inside a particular method of a particular class, in which case I want to be failing the relevant test. Unfortunately, a text-based approach is purely unsatisfactory, because it would also catch
potential references to Arrays.sort from within source code comments, for instance. Any help appreciated.
You can do it by creating your interface for sorting and an implementation that uses Arrays.sort
public interface SortUtil {}
public class SortUtilImpl implements SortUtil {
public void sort(Collection c) {
Arrays.sort(c);
}
}
Now you must use the interface in your 'client' class for sorting. For unit tests, replace the real implementation by a test mock one. like:
public SortUtilMock implements SortUtil {
public void sort( Collection c) {
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
//... here you check if the sort is called by a forbidden method
}
}
Best regards,
Zied

Is it a right case for Mockito spy?

Let's say I have a class
class SomeClass
{
public void methodA()
{}
public void methodB()
{}
public void someMethod()
{
methodA();
methodB();
}
}
I would like to test behavior of someMethod() with Mockito.
The only way I could think of is using spy();
Something like
SomeClass someClass = spy(new SomeClass());
someClass.someMethod();
InOrder inOrder = inOrder(someClass);
inOrder.verify(someClass).methodA();
inOrder.verify(someClass).methodB();
I'm new to the mockito and documentation says
"Real spies should be used carefully and occasionally, for example when dealing with legacy code."
So maybe I'm missing something and there is better (right) way to verify that methodA and methodB were called without explicitly calling them in the test case.
Thanks.
Yes, spy() is fit for your purpose. The warning is due to the fact that real methods are invoked, and hence you can get unexpected results (for example - real money being withdrawn from a bank account)
If your code needs spy for unit testing - something wrong.
Spy is a first sign of a code smell.
You have two options to avoid it in your example:
You can avoid mocking one of the method and test the whole someMethod.
If methodA and methodB is really needs to be mocked - you can move them to seperate class etc.

Categories