Unit-test wrapper methods when base method is private [duplicate] - java

This question already has answers here:
How do I test a class that has private methods, fields or inner classes?
(58 answers)
Closed 6 years ago.
I read this answer about unit-test a wrapper method. In following code:
public static Object methodA(Object arg) {
if (arg == null) {
return null;
} else {
return methodB();
}
}
It looks reasonable that I don't need to test all functionality in methodB(), just test 2 cases where arg is null and not because methodB() should be tested already.
However, if methodB() is private method, I should test all functionality that methodB() will provide because according to another answer, private methods are implementation details.
The problem is, if I have 2 methods methodA1() and methodA2() and they all call methodB() like this:
public static MyObject methodA1(int x) {
MyObject obj = new MyObject();
obj.setX(x);
return methodB(obj);
}
public static MyObject methodA2(int y) {
MyObject obj = new MyObject();
obj.setY(y);
return methodB(obj);
}
private static MyObject methodB(MyObject obj) {
// doSomething with obj
return obj;
}
Should I test methodA1() and methodA2() separately? Or I can just test the private method methodB() because methodA1() and methodA2() are just wrapper methods of methodB(), so if methodB() is correctly tested, I won't need to test methodA1() and methodA2() at all.
EDIT:
I wrote separate tests for public methods at first. But the problem is, if there are many variations of the methodA, and some of the functionalities / requirements are shared in some of them, then the code of the test cases will be duplicated. That's why I wonder if I should test private method methodB().
The real problem I met is I have requirement to add a record in database, and there are many different APIs I should provide. For example, I should provide:
MyObject addMale(String name, String job); // fill sex with "Male"
MyObject addStudent(String name, String sex); // fill job with "Student"
And all of them checks the parameter is valid or not, fill the field that is not specified and call the private method to actually insert the record into the database, which is so called methodB().
There are many APIs like this, so if I can only test methodB() with all fields situation, maybe I can reduce the duplication of the test cases, but is that a good practice to do the unit tests like this?
EDIT2:
I know I can test private methods because I used reflection in my other test cases, and I know it can invoke private methods, too. But my question is about in this situation, testing private methods is a proper solution or not.

This is actually a question I've wondered about for awhile, and while it's not necessarily correct, I'll share my opinion.
The main problem is that private methods are hard to test. I did some Googling, and there some tools and techniques that let you access private methods (reflection is the main one I encountered), but they seemed a little convoluted.
But the reason you wrote a private method is because there is another method, a public method, that calls it. So while you can't directly test the private method, you can check its functionality by testing the public method which calls it.
If I were you, I would extensively test methodA1() and methodA2(), ensuring that all the functionality of methodB() is tested by the tests you run on the public methods.

You've received a few opinions why you should write unit tests for methodA1() and methodA2(); you've pushed back on them. You asked the question here; you are clearly looking for some justification for not writing complete unit test for them. Let's see if we can give you the answer you want. ;-)
From what you've added in your edit, it looks like you have a variation on a builder pattern. Eg)
MyObject o = new Builder().setX(1).setY(2).setZ(3).setW(4).build();
How would we test the builder?
Since the builder has 4 attributes, which could be set in any order, there would be 4! = 24 different orderings. A complete test suite would have to include:
#Test public void testXYZW() { ... }
#Test public void testXYWZ() { ... }
// ... 21 more permutations ...
#Test public void testWZYX() { ... }
But is that all? No! Some of those attributes could have default values, so we would have to test those patterns as well. Total orderings is now P(4,4)+P(4,3)+P(4,2)+P(4,1)+P(4,0) = 24+24+12+4+1 = 85 unit test.
#Test public void testXWY() { ... }
#Test public void testWY() { ... }
#Test public void testZ() { ... }
// ... 61 more permutations ordering
And this only tests each permutation of X, Y, Z, W attributes with one test value per attribute per test. It is clearly unwieldy to write an exhaustive set of tests for every possible combination and permutation.
The designer of the builder class would understand that the permutation of the attribute settings does not affect the resulting construction; writing tests for permutations of the order does not actually increase the test coverage. Tests for omitted attributes are useful, as they test the default values. Testing of different combinations of the omitted attributes again would not increase the test coverage. So, after careful thought, only two tests might be required:
#Test
public void testXYZW() {
MyObject o = new Builder().setX(1).setY(2).setZ(3).setW(4).build();
assertThat(o.wasBuiltProperly());
}
#Test void testDefaults() {
MyObject o = new Builder().build();
assertThat(o.wasBuiltProperlyFromDefaults());
}
If proper, complete testing of methodB() is being done, then you could safely get away with testing only the validation of inputs in methodA1() and methodA2().
#Test void testMethodA1Professor() {
MyObject o = methodA1("professor");
assertThat(o.wasBuiltProperlyWithProfessor());
}
#Test void testMethodA1WithNull() {
MyObject o = methodA1(null);
assertThat(o.wasBuiltProperlyWithNull());
}

Oftentimes, when a private method is used by multiple methods inside a class, there's a distinct concept lurking behind it. It may deserve to have its own class.
it should not be used outside of the class
There are a few ways you could extract methodB to its own class and not make it available as part of your public API :
Nest it inside the class that uses it and give it a restricted scope
Put it in another module at a lower level. Make that module available from your API but not from the clients.

Related

How to assert the number of assertions (or some other way to enforce that all members have been tested in an assertion)?

In a certain unit test for my class, I want to assert that an assertion has been written for all member fields. That is, given
public class Foo {
int a;
int b;
String c;
}
I want to do something like
#Test
public void testFieldsAgainstExternalModel(Foo model, Bar externalModel) {
assertEquals(model.a, externalModel.getA());
assertEquals(model.b, externalModel.getSomethingNamedDifferently());
assertEquals(model.c, externalModel.getC().toString());
assertNumberOfAssertionsInThisTest(3); // <-- How do I do this?
}
Of course, counting the number of assertions doesn't ensure that they had anything to do with each field having an assertion. But, I'm just trying to write a test that fails if a developer adds a field to Foo and forgets to update this test.
Naivest approach: The simplest thing I can think of is to use reflection to assert the number of fields Foo has, e.g. assertEquals(3, Foo.getDeclaredFields().count()). But, I can easily see a programmer bumping up the number without actually adding an assertion.
Still a naive approach, but acceptable: I think if I can at least count the number of assertions, it would sufficiently guide programmers toward the intended need.
More exact approaches: Of course it seems to best approach is to actual keep a table of which fields have appeared in the assertion (e.g. through a wrapper method like assertEqualsWithCounters), but in reality my situation's a little more complicated. For example, my model is actually a generated class (#AutoMatter) and I'll be using getters on both sides of the assertion, so it'll be hard to infer truly which field has been "touched" by an assertion. That's why just counting assertions and remaining agnostic to actual types and counts, would be easiest for me.
But, I'm just trying to write a test that fails if a developer adds a
field to Foo and forgets to update this test.
My company uses a mapping framework to map beans from the db, fields are one to one with the database, to a model bean we return to the client that we can modify as needed. I believe this is a common use case and essentially what you are trying to get at. You should be less concerned with testing changes to Foo, and more concerned with ensuring nothing breaks with the mapping from Foo to Bar.
Class BeanDb{
private int a;
private int b;
...
}
Class Bean{
private int a;
private int b;
private String somethingElse;
...
}
Then we have have a proivder test that uses isEqualToComparingFieldByFieldRecursively to compare the two beans.
private Bean bean = new Bean();
private Bean beanDb = new BeanDb();
private BeanProvider provider = new BeanProvider();
#Before
public void setup(){
bean.setA(1);
bean.setB(2);
beanDb.setA(1);
beanDb.setB(2);
}
#Test
public void prepareForDatabase(){
BeanDb db = provider.prepareForDatabase(bean);
assertThat(beanDb).isEqualToComparingFieldByFieldRecursively(db);
}
#Test
public void populateFromDatabase(){
Bean model = provider.populateFromDatabase(beanDb);
assertThat(model).isEqualToComparingFieldByFieldRecursively(bean);
}
This actually catches a lot of bugs. If something changes in the model bean / db bean the test will break in our continuous integrations suite. The caveat here is that isEqualToComparingFieldByFieldRecursively will not catch newly added fields.
When I review code / pull requests and BeanDb or the provider has been updated I ask, "Did you update the provider test?"
I think you may need to use PowerMockito as Mockito does not support mocking static methods.
I haven't tested the code below - but my idea would be to do the following:
#RunWith(PowerMockRunner.class)
public class Tester {
public class Foo {
int a = 5;
int b = 6;
String c = "7";
}
class Bar {
public int getA() {
return 5;
}
public int getSomethingNamedDifferently() {
return 6;
}
public Integer getC() {
return 7;
}
}
#Test
public void testFieldsAgainstExternalModel() {
testFieldsAgainstExternalModel(new Foo(), new Bar());
}
public void testFieldsAgainstExternalModel(Foo model, Bar externalModel) {
Assert spiedAssert = PowerMockito.spy(Assert.class);
spiedAssert.assertEquals(model.a, externalModel.getA());
spiedAssert.assertEquals(model.b, externalModel.getSomethingNamedDifferently());
spiedAssert.assertEquals(model.c, externalModel.getC().toString());
PowerMockito.verify(spiedAssert, times(3)).assertEquals(any(), any());
}
}
I think that the answer to
assertNumberOfAssertionsInThisTest(3); // <-- How do I do this?
is: you do not do that. This test is close to useless.
If there are only 3 fields, you can see with your eyes that you are checking those three fields. You are probably thinking about 15 fields in that class, but then:
assertEquals(model.a, externalModel.getA());
assertEquals(model.b, externalModel.getSomethingNamedDifferently());
assertEquals(model.c, externalModel.getC().toString());
assertEquals(model.c, externalModel.getC().toString());
assertEquals(model.d, externalModel.getD().toString());
...
assertEquals(model.o, externalModel.getO().toString());
assertNumberOfAssertionsInThisTest(15);
would not help you. Guess what: when pulling together my faked example, I omitted property 14 (model.n), but instead I had a copy/paste error and checked model.c two times, leading to an overall count of 15.
Therefore I agree with user Phil, just suggesting yet another approach, like this:
ensure that the bean classes have reasonable equals() (and maybe hashCode() methods). Either by using Lombok, or by having a base bean class that makes use of an EqualsBuilder (we actually do the later in our projects)
then have test code either use a faked bean and simply compare if that faked bean is equal to the bean that your production code created from a (maybe faked) external model object.

How to mock a local variable b (which uses private method) without using power mockito?

public class A {
public void methodOne(int argument) {
//some operations
B b = methodTwo(int argument);
// some operations based on b
// switch cases based on returned values of b
}
private void methodTwo(int argument)
DateTime dateTime = new DateTime();
//use dateTime to perform some operations
}
If you really must mock class B, then you can do it as follows (without using PowerMock, but instead the JMockit library):
public class ExampleTest {
#Tested A a;
#Test
public void exampleTest(#Mocked B anyB) {
// Record calls to methods on B, if/as needed by code under test:
new Expectations() {{ anyB.doSomething(); result = "mock data"; }};
// Exercise the code under test:
a.methodOne(123);
// Verify a call to some other method on B, if applicable:
new Verifications() {{ anyB.someOtherMethod(anyString, anyInt); }};
}
}
Note this test does not care how A obtains B. It is independent of implementation details such as private methodTwo, as a good test should always be.
Ideally, you don't!
Meaning: your methodOne() is returning a certain value. So, if possible, you should prefer to not test internals.
Thus, you should write test cases that invoke methodOne() with various parameters; and then assert that the value returned by that method matches your exceptions.
If you really need to control that "B" object in order to do reasonable testing, the correct way to get there is to use dependency injection and provide a B object to your class under test somehow. Because then you can create a mocked B and hand that to your class under test.
In other words: learn how to write testable code; for example by watching these videos. Seriously; each minute of that material is worth your time.

Is reflection execute the method in sequence order?

I have a class file, and I just want to get the list of methods name in that class and print it o/p console.
Just assume that I have following methods in Test1 class
public class Test1{
public static void test1()
{
//some code
}
public static void test2()
{
//some code
}
public static void test3()
{
//some code here.
}
}
I just need to call all the above methods from another class in the specific order.
Like test1() first, and second test2() and followed by test3();
What I did like I just created
Method[] methodarray=Test1.getMethods();
if(methodarray.getName().startWith("test"))
{
sysout(methodarray.getName())
}
The above code print the method in specific order first time but not always. some times it prints 3rd method first and 1method seconds, and finally 2 method.
Can anybody tell me the reason?, and how to resolve this?.
-Sasi
Quote from the JavaDoc: "The elements in the returned array are not sorted and are not in any particular order.".
First of all, it's always best to avoid reflection where possible in a project. Most of the time it's used for testing purposes, or if there really is no other way. That being said, if your methods are indeed called test1, test2 and test3 and you want to execute them in this order, you can use the following steps:
Get all methods from the class (you've done that correctly with Method[] allMethods = Test1.getMethods();)
Loop through them and save all which start with "test" in a seperate list
Order that list with a Custom Sorting to sort the Methods of the seperate list by Method-Name. (See here for an example.)
Invoke & Execute them
Still, it takes three loops (or some Java 8+ LINQ-queries) and it doesn't make the code very clear to anyone, including yourself. It's better to just execute them one by one manually, i.e.:
public void someMethod(){
Test1.test1();
Test1.test2();
Test1.test3();
}
That's just my 2c. From the question it wasn't clear what the purpose of the methods are, or if there are more than three. I would suggest keeping away from reflection unless you really have no other way.
As you can read in the javadoc for getDeclaredMethods(), the returned Method[] doesn't follow a particular order.
You can sort the methods easily by using a LinkedHashMap, or any other Map implementation, that maintains order of elements. For example:
public class MethodTest {
private LinkedHashMap<String, Method> expectedMethodsInOrder;
void testOne(){
}
void testEight(){
}
void beforeEight(){
}
#Before
public void prepareMap(){
expectedMethodsInOrder = new LinkedHashMap<>();
expectedMethodsInOrder.put("testOne", null);
expectedMethodsInOrder.put("beforeEight", null);
expectedMethodsInOrder.put("testEight", null);
}
#Test
public void test(){
Method[] methods = MethodTest.class.getDeclaredMethods();
for(Method m : methods){
String name = m.getName();
if(expectedMethodsInOrder.containsKey(name)){
expectedMethodsInOrder.put(name, m);
}
}
System.out.println(expectedMethodsInOrder.values().toString());
}
}
Output:
[void Main.testOne(), void Main.beforeEight(), void Main.testEight()]
It's working as expected in Windows 7 but not in Windows 8. I have same setup on both environments, like JAVA JDK7, and Eclipse IDE JEE build. But reflection returns the method as Its mentioned in respective class file. But not in Windows 8. It seems to be environment issues.
I just wanna update my things which I observed. Please correct me If there is any other root cause.
-Sasi

Mocking with functionality

I am very new to Mockito, please let me know if I'm on the right track. I'm trying to mock method functionality using Mockito.
sscce
public SUTclass {
private final DependencyInjectedObj dep; // already successfully mocked
private int statefulInteger;
private int otherInteger;
public int doSomething() {
return otherInteger + dep.doMath(statefulInteger);
}
}
Right now, dep is mocked... but dep.doMath always returns 0. In production, dep is stateful - no way to avoid it. In production, a different thread updates its state in real time. dep.doMath does some funky calculations depending on the state right now. You could imagine that production functionality might look at a thermometer and do something with it's temerature, and doSomething gives a realtime status based on that temperature.
In my test, though, I'd like to have dep.doMath have this functionality (which is a sufficient approximation for a unit test):
public int doMath(int input) {
return SOMECONSTANT * input;
}
I suppose I could create a Mock implementation of DependencyInjectedObj and use that, but that seems to defeat the purpose of using Mockito and the when syntax. What should I do?
In this case, what you want is doAnswer(). It allows you to execute arbitrary code when a mock invocation is called:
doAnswer(new Answer<Integer>() {
public Object answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
int i = (int)args[0];
return i * CONSTANT;
}
}).when(dep.doMath(any(Integer.class));
I do consider doAnswer a bit evil, though. Generally thenReturn(CONSTANT) is sufficient for most unit tests. If you're going to verify the result of this method call, then you're testing the wrong class -- the point of mocking your dependencies is you don't much care about their operation.

Mockito - Feeling that I don't use its full potential

When using Mockito, I only use it to mock out dependencies, i.e. my workflow looks mostly like this:
I have a class with dependencies:
public class C {
public C (A a, B b) {
this.a = a;
this.b = b;
}
public String fooBar() {
return a.foo() + b.bar();
}
}
In my test class, I mock out those dependencies, and tell them which values to return when some specified methods are called:
public class CSpec {
private A a = mock(A.class);
private B b = mock(B.class);
#Test
public itShouldReturnFooBar() {
when(a.foo()).thenReturn("foo");
when(b.bar()).thenReturn("bar");
C c = new C(a, b);
assertThat(c.fooBar().isEqualTo("foobar"));
}
}
(I hope this example is not too simple or too derived ;-)). This works fine, it allows me to test classes (here: C) in isolation. Still, I never use Mockito's verify methods or any other of its features. Is it okay / sufficient to use Mockito this way?
Verify would be typically used to check that your C really calls the A.foo() and B.bar() methods. So you could add
verify(a).foo();
verify(b).foo();
before or after the assertThat. I don't think you need or should use them here but there are several situations where you would need that:
a or b does something that is not visible / reachable from c's public API (for example logging)
You are concerned with the order of execution
You want to make sure that only a.foo and b.bar methods are called, nothing else like a.foo2
You could use those mocks as spy's, so that call to a.foo would be then routed to the aReal.foo
The verify approach is particularly useful in a Tell Don't Ask style of programming.
Consider the following version of your class C:
public class C {
public C(A a, B b, CListener L) { ... }
...
public void foobar() {
String result = complexPrivateMethod(a, b);
L.fooBarred(result);
}
}
Thus, rather than just computing the result, you inform some interested party (e.g. a user interface) about the result.
To test foobar now, you'd want to verify that the listener is correctly invoked:
public class CTest {
#Mock CListener mockListener;
...
#Test itShouldTellCAboutFooBar() {
C c = new C(stubbedA, stubbedB, mockedListener);
...
verify(mockedListener).fooBarred("foobar");
}
}
This use of verify is typical for Test-Driven Development: See Freeman & Pryce's Growing Object-Oriented Software Guided by Tests.
Thus, if you want to use the full potential of Mockito (the question), you most of all need to adopt the corresponding design philosophy in your code.
Yeah, there's no problem with this test, it's perfectly fine. The simple fact the the stubs are being used make the test working, if you remove or change the stubs then the test won't work.
Adding verify statements will just make things redundant in this kind of tests.
However if you precisely want to verify arguments, the order or number of interactions or something else then you definitely want to add checks on the interactions between the tested object and his collaborators.
It is totally ok to use Mockito just this way. But if your code gets more complex you need to do some more things to get your code tested as simple as possible.
Another small example:
public void eitherAorB() {
if(somethingIsTrue) {
a.doSomething();
} else {
b.doSomethingElse();
}
}
You might want to make sure, that the expected method is called on the expected object.
#Test
public doSomethingShouldBeCalledOnA() {
A a = mock(A.class);
C c = new C(a, new B());
c.setSomeThingIsTrue(true);
eitherAorB();
verify(a).doSomething();
}
#Test
public doSomethingElseShouldBeCalledOnB() {
B b = mock(B.class);
C c = new C(new A(), b);
c.setSomeThingIsTrue(false);
eitherAorB();
verify(b).doSomethingElse();
}
In other cases you might want to know which paramater was passed into a method. For that you need an ArgumentCaptor.
Or in some cases you need to call the actual method or use an actual object (no mock), so it is time to spy on an object and capture arguments or verify behavior.
So there is a lot more to Mockito you might need once in a while.
The answers given so far are good, but there are additional features you didn't mention either. The #Mock, #Spy, #InjectMocks annotations are all very useful. Along with the verify(...) methods, there is also the InOrder class to help verify the order of method calls. And perhaps you use the matcher methods already (<T> any(T t), anyString(), etc), but you don't show that you use those facilities.

Categories

Resources