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.
Related
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.
I am looking for a way to test the data in a class that processes the data and then uploads the data in a manner as clean and portable as possible. So I would like to not resort to making public get functions, to avoid anything being able to reach this data. To keep it portable, I would like to avoid using a test database, so that these tests can be ran in any situation.
Class Foo {
private int a;
private int b;
private int c;
private DBSaver dbSaver;
public Foo(DBSaver dbSaver) {
this.dbSaver = dbSaver;
}
public void processData() {
processData();
saveToDB();
}
private void workNumbers() {
a = 1;
b = 2;
c = a + b;
}
private void saveToDB() {
List<Integer> list = new ArrayList<>();
list.add(a); list.add(b); list.add(c);
dbSaver.save(list);
}
}
Test class:
class FooTest {
#Mock
DBSaver dbSaver;
#Mock
Foo foo;
#Test
private void test() {when(dbSaver.save(any(ArrayList<>.class))).then(returnsFirstArg());
foo = new Foo(dbSaver);
Mockito.doThrow(new Exception() {
//Now I would like to get a, b and c so I can ensure that they have the proper values.
}
).when(foo).processData();
}
}
Here is a pastebin version of the code]().
workNumbers() will be executed as normal, and since the save() function has been mocked to do nothing, that code won't do anything too serious.
I would like to ask if there is a way to now get the a, b and c values back in list form, through mocking an exception being thrown. The problem is accessing the private values in Foo through the mocked instance in FooTest.
You are getting unit testing with mocking wrong. There is no point in having this:
#Mock
Foo foo;
Foo is your "class under test". You do not want to mock that. If at all, you might want to create a spy here, in order to do partial mocking.
In your case, you don't need to access those private fields. You see, the key point is that your code will call:
dbSaver.save(list);
at some point. Meaning: you can use Mockitoy to verify that a specific list is passed when save() is called on that mocked dbSaver object.
That is the whole point: you have that mocked dbSaver instance, so you are in total control what happens there. As said, you can verify that its methods are called with a specific argument; or you can even use an ArgumentCaptor in order to access the list passed to that method call.
And then you simply ensure that the list contains the expected content (which would be those three values from your class under test!). See
here for examples how to do that.
Finally: especially that "exception" part is really wrong. There is no need to generate an exception here. You simply push a mocked dbSaver into an instance of Foo, you call a method on that Foo instance; and then you check for the expected results. That's it; anything else is (useless) over-complication of things.
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.
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.
Suppose I following classes:
class A {
private B b;
private int milkQuantity;
A(B b) {
this.b = b;
}
public getCoffee() {
milkQuantity = b.getMilk(1);
return secretRecipe();
}
...
}
So, while unit testing should I mock class B and check if getMilk() method was called or I should check if it returns the correct milk quantity(i.e 1 cup)? for the latter case I need to setup class B in my unit test.
According to me we need to check the behavior of class B in its own unit test, class A should be concerned only if the correct method was called or not.
Update 1
Making my point more clear:
on calling a.getCoffee() should I test:
assertThat(a.milkQuantity).isEqualTo(1);
OR
verify(b).getMilk();
When writing unit tests, you need to handle each unit (usually - a class) in its own test. SO B needs its own test and A needs a test with a mocked instance of B to test its using it correctly. You don't need to check getMilk's return value (after all - you're mocking it), but you do need to check that B is using it correctly - i.e. that secretRecipe is being called with the same value getMilk returned.
Ideally, you would want to test the behavior of getCoffee and not how it's implemented. Perhaps in the future you will implement it differently but with the same behavior and that shouldn't break your unit test. So I would recommend just testing the result of getCoffee. It's fine to mock b.getMilk.
When testing I would recommend doing something like
B b = new B() {
#Override
public int getMilk(int x){
// Mock implementation
}
}
A a = new A(b);
Coffee expected = ... // Manually construct a Coffee object with expected values
assertEquals(expected, a.getCoffee())