Dagger2 + Mockito: How to Unit Test this scenario? - java

I'm working on a team project which has a very coupled code. I'm trying to increase the unit test coverage and I've faced the following scenario:
class Foo {
static void methodA () {
Bar b = new Bar();
b.getContent();
}
}
class Bar {
#Inject
DBAcessor mDBAcessor;
Bar () {
Dagger2.getInjector().inject(this);
}
public Object getContent() {
mDBAcessor.fetchData();
}
}
I want to unit test methodA(), however I don't know if it is possible to do it without passing the DBAcessor object via constructor to Bar() class. Bar should be a POJO model being widely used throughout the project, hence, I don't know if it would be a good idea to change its constructor and impact so many other classes. Any tips on how should I approach this scenario?

That is wrong design.
Whenever you have an access to the constructor, pass class dependencies into constructor. That really eases unit testing. Class Bar should look:
class Bar() {
#Inject DBAcessor mDBAcessor;
Bar (DBAcessor dbAcessor) {
this.mDBAcessor = dbAcessor;
}
public Object getContent() {
mDBAcessor.fetchData();
}
}
Dagger2 methods declared in Component should only be used inside object you don't have an access to the constructor (Activity or Fragment).
Then nothing prevents you from doing that:
DBAccessor dbAccessor = Mockito.mock(DBAccessor.class);
Bar bar = new Bar(dbAccessor);
bar.getContent();
verify(bar, times(1)).fetchData();
If you really need to stick to such design, then you can't make unit tests on such object, as Dagger2 depends on Application object, which needs Context, which you cannot emulate in unit tests. Write your test as androidTest, create appropriate Activity, fetch Bar object from it and test it.

Related

Injecting a Bar with an already existing Foo

Consider the existence of a Foo some time in the app. Now Bar objects depend on a Foo. I want to create this bar based on this foo I already have, but Guice creates a new instance of Foo every time. I can have a lot of Foos, so I cannot #Singleton Foo.
I tried to use scopes for this purpose, but I don't know what I am doing wrong.
I know this can be solved with #AssistedInject but I do not want to take this solution because these associations are common in my context and the dependency is only one. Also, since I am working on creating a tool based on Guice, all I got is a Foo, and Bar.class and I want to create instances of Bar with the given Foo. I am not aware if there are any factories or so.
public class InjectionTest2 {
public static void main(String[] args) {
Module module = new AbstractModule() {
ReceiverScope receiverScope = new ReceiverScope();
#Override
protected void configure() {
bindScope(ReceiverScoped.class, receiverScope);
bind(Foo.class);
}
#Provides
#Singleton
public ReceiverScope scope() {
return receiverScope;
}
};
Injector injector = Guice.createInjector(module);
Foo foo = injector.getInstance(Foo.class); //assume a given foo
ReceiverScope scope = injector.getInstance(ReceiverScope.class);
scope.enter();
scope.seed(Key.get(Foo.class, Existing.class), foo);
Bar bar = injector.getInstance(Bar.class);//Create a Bar with this foo
scope.exit();
}
private static class Foo {
#Inject
public Foo() {
System.out.println("foo created" + toString());
}
}
#ReceiverScoped
private static class Bar {
#Inject
public Bar(#Existing Foo foo) {
System.out.println("bar created with foo" + foo.toString());
}
}
#Retention(RetentionPolicy.RUNTIME)
#BindingAnnotation
private static #interface Existing {
}
}
ReceiverScope is a class identical to Simple Scope given here.
Another way I can think of is if I manually iterate Bar's contructor parameters and for each parameter, I ask guice to give me an instance, but if it is a Foo, I give my value. But won't this give me a very hard time? I mean I will have to consider a lot of things, because in the constructor might be extra Qualifiers on parameters and stuff...
EDIT (after #kendavidson's answer):
This is true. I thought it makes my question more complicated, that's why I did not include it. Bar is an interface. Fields in Foo contain an annotation which has a Class<? extends Bar> barClass() method. For example:
#ContainsBars
private static class Foo {
#MakeBar(BlueBar.class)
private Something aSomething;
#MakeBar(BlackBar.class)
private SomethingElse aSomethingElse;
#Inject
public Foo() {
//create aSomething
//create aSomethingElse
}
}
Now, whenever Guice injects a #ContainsBars, I listen it via a TypeListener and I go to create the bars. I scan Foo.class and I get BlueBar.class & BlackBar.class.
The problem I am trying to solve is, how to create BlueBar when BlueBar has a dependency to Foo.class? Whenever this happens, I need to create the BlueBar with the Foo I was taken from the listener.
Reflecting constructor was one of my thoughts however it sounds a pain in the ... I guess, it will need to iterate each parameter of the #Inject constructor of BlueBar.class. If the parameter is of type Foo, I give my Foo. If it is a different type, ask the injector to give me an instance of that type. The thing is, how do I do this. When Guice injects, it takes in consideration possible binding annotations (Qualifiers) and generics. Doing that again, sounds pain.
In the other hand, these #ContainsBars annotated classes by 99% chance have no relation to each other.
Adding a method to Bar interface like setFoo(Foo f) will not work. It will have to be a generic. Therefore, method injection with a setter will be cast unsafe. As far as I am aware of, and assuming BlackBar implements Bar<Foo>, when I will Bar b = injector.getInstance(BlackBar.class), It will give me a Bar<?>. That means, I can't call the setter safely.
Field injection is interesting. Having something like this:
public class BlackBar implements Bar {
private MyDepedency dep;
#Existing
private Foo foo;
public BlackBar(Foo foo,MyDepedency dep) {
this.foo = foo;
this.dep = dep;
}
}
seems ok. Whenever, I get a BlackBar, I go find the #Existing field, and then set the value. I do not care for the value in constructor. Let's say:
Foo foo = ...
Bar bar = injector.getInstance(BlackBar.class);
setExistingFieldWithValueOf(foo,bar);
The problem here is that whenever I ask injector, it sees the Foo dependency, and it is creating a new Foo in order to inject. Then, I go change its value. This will cause an infinite loop since during Foo injection which is a #ContainsBar, the process will be repeated. Even if i manage to stop the infinite loop, still the creation of a new Foo that will never be used seems a bad overhead. If there is a way to inject with null value to foo in the constructor, let me know. I will use this.
This might be a shot in the dark and if I'm missing something please let me know. First off, I definitely think AssistedInject is a solid choice, with a minimal footprint for each Bar.
A couple things missing from your question and comments are:
What are some sample annotated fields of Foo?
How do you expect multiple Bars to be created?
Are you dealing with Bar and OtherBar implementations? Or are you dealing with Bar and <T extends Bar> interface?
Based on some of these things, it might be doable with:
// BarProvider.java
public class BarProvider {
// Get the injector, frowned upon but required
#Inject Injector injector;
public <T extends Bar> T get(Foo foo, String fieldname) {
// Provider right now returns on Bar at a time, I'm guessing this is based on
// fieldname, which can lookup the #Annotation to get the class
Annotation annotation = ...;
Bar bar = ...;
// Now you need to create the bar, this can be done in a couple of ways:
// Option 1 is to reflect the Bar(Foo) constructor
// then doing an injector.injectMembers(bar) to fill the remaining fields
// Option 2 is to use field/method injection and doing a combination of
// Bar bar = injector.getInstance(annotatedClass); followed by
// bar.setFoo(foo);
return bar;
}
}
// Foo.java
public class Foo {
}
// Bar.java
public interface Bar {
}
// ABar.java
public class ABar {
}
// BBar.java
public class BBar {
}
In both cases you would not #Inject the Foo field in Bar. Again this makes some assumptions on how you know which field you want to look at in Foo for the annotation class type.
Another option would be to return all of them using:
public <T extends Bar> T[] get(Foo foo) {
// Same thing but loop through all Annotated fields
}
In both cases I'm assuming that Bar and OtherBar are actually implementations of the same interface which means you'd always be using Bar as a return type. It's still possible otherwise, just a little more annoying.
Hopefully I'm not way off base, and something might be helpful. But again AssistedInject the way it was described above would still probably be a better solution.
Edit 1 - Circular Dependencies
If you have these classes, for example, you will not have issues with Foo being injected and then overwritten.
public abstract class Bar<T> {
T foo;
setFoo(T foo) {
this.foo = foo;
}
}
public class BlackBar extends Bar<Foo> {
#Inject Dep1 dep1; // Injected
#Inject Dep2 dep2; // Injected
BlackBar() {}
}
#ContainsBar
public class Foo {
#BlackBar
SomeObject someObject;
}
Now in your example:
Foo foo = injector.getInstance(Foo.class); // Inject SomeObject
Bar bar = injector.getInstance(BlackBar.class); // Inject Dep1 and Dep2
bar.setFoo(foo); // Set Foo manually
This won't cause the problem you think it does, because Foo foo is NOT annotated with #Inject therefore Guice won't create a new one when building BlackBar.
But this still doesn't answer how exactly you're USING your bars. I also have a feeling I'm missing something very important to the end goal.

Different ways of mocking object creation in Mockito?

I see a couple different ways of mocking objects. What exactly are the differences between this approache using InjectMocks and the approach shown here: https://github.com/mockito/mockito/wiki/Mocking-Object-Creation?
#ExtendWith(MockitoExtension.class)
public class MyTest() {
#Mock ClassB uut;
#InjectMocks ClassA cA;
#Test
public TestOne() {
...
}
}
where
public class ClassA() {
public ClassA() {
ClassB temp = new ClassB();
}
}
versus the method shown here:
https://github.com/mockito/mockito/wiki/Mocking-Object-Creation
What exactly is the difference?
I believe there is no essential difference between those approaches.
InjectMocks approach
Actually for it to work, your class should accept the dependencies through the constructor or setters (and it never works with both). I would say that this approach makes the testing easier because you inject whatever you want to your class object at the initialization phase.
class Foo {
private final Bar bar;
public Foo(final Bar bar) {
this.bar = bar;
}
}
If this is our class under test, then all #InjectMock does is to create mocks, and do the following:
Foo foo = new Foo(barMock);
Apart from being testable, imagine if the Bar is an interface, then you can possibly you can switch between multiple implementations of it without actually touching the class code (ideally). If you have a DI framework, that's even easier. So, basically this format of the class makes it flexible.
Using one-line methods for object creation
Let's say this is our class under test. As you can see, I am initializing the property inside the constructor. Legally, with no reflection magic, I cannot put a mock bar variable neither during initialization nor after that.
class Foo {
private final Bar bar;
public Foo() {
this.bar = new Bar();
}
}
The reason that Mockito docs tell you to switch to either a one-liner method or a Factory helper is that:
Mockito cannot mock constructors, which means you cannot put a mock object in the place of bar without reflection, and you can only do that after the initialization. Generally, to point of my view on testing, reflection should be avoided as much as possible.
One-liner functions are looking as clean as constructors and they can be descriptive (like static factory methods).
So, when you switch your class to look like this:
class Foo {
private final Bar bar;
public Foo() {
this.bar = makeBar();
}
Bar makeBar() {
return new Bar();
}
}
Now, you can put a spy, and just mock the makeBar method easily. The same applies to the factory method as well. To be honest, the factory approach looks a bit wordy to me, but still, I am sure there will be times when it may come handy.

How can we test that a class implements many interfaces?

My question is about testing a class that implements many interfaces. For example, I have this class:
public class ServiceControllerImpl extends ServiceController implements IDataChanged, IEventChanged {
}
Now there are two ways for testing. The first is testing directly on the concrete class. That means the object type is the concrete class rather than the interface.
public class ServiceControllerImplTest {
ServiceControllerImpl instance;
#Before
public void setUp() {
instance = new ServiceControllerImpl();
// you can bring this instance anywhere
}
}
The second way is testing on the interface only. We must typecast this object to all interfaces it implements.
public class ServiceControllerImplTest {
ServiceController instance; // use interface here
IDataChanged dataChangeListener;
#Before
public void setUp() {
instance = new ServiceControllerImpl();
dataChangeListener = (IDataChanged) instance;
// instance and dataChangeListener "look like" two different object.
}
}
I prefer the second solution because maybe in future we can change the interface it implements to other objects, so using the concrete class might lead to failing tests in the future. I don't know the best practice for this problem.
Thanks :)
I prefer second solution because in reality, maybe in future we can change the interface it implements to other objects, so force using concreted class maybe leads to fail test in the future.
I guess it will lead to failed tests anyway, because you usually test that assertions are true or false. The question is: Do that tests apply to any IDataChanged or do these assertions only apply to the ServiceControllerImpl?
If the assertions only apply to the ServiceControllerImpl it doesn't matter if you use an IDataChanged instead of an ServiceControllerImpl, because you must edit the test when you use another IDataChanged object - different assertions. The test will fail if you use another object.
The way you setup unit tests Itself gives you an answer. A unit test usually tests one class in isolation. This means that you mock the environment. But mocking the environment means that you know the dependencies of the class you test and this are implementation details. So your test is written on an implemtation basis rather than only the interface.
It's possible to write tests that only test an abstract api - like an interface. But this usually means that your tests are abstract too. E.g.
public abstract class SetTest {
#Test
public void addAlreadyExistentObject(){
Set<String> setUnderTest = createSetUnderTest();
Assert.assertTrue(setUnderTest.isEmpty());
boolean setChanged = setUnderTest.add("Hello");
Assert.assertTrue(setChanged);
setChanged = setUnderTest.add("Hello");
Assert.assertFalse(setChanged);
Assert.assertEquals(setUnderTest.size(), 1);
}
protected abstract Set<String> createSetUnderTest();
}
You can then extend these abstract tests to test the api for concrete classes. E.g.
public class HashSetTest extends SetTest {
#Override
protected Set<String> createSetUnderTest() {
return new HashSet<String>();
}
}
In this case you can replace the implementation and the test must remain green.
But here is another example of an abstract api when replacing the object under test does not really make sense.
What about writing a test for all Runnables?
public class RunnableTest {
#Test
public void run(){
Runnable runnable = ...;
// What to test here?
// run is invoked without throwing any runtime exceptions?
runnable.run();
}
}
As you can see it does not make sense in some cases to write tests in a way so that you can easily replace the object under test.
If an api like the Set api defines a concrete state handling you can write abstract tests that test this.
JayC667 already correctly answered that it's best to refer to a class through its supertype(s) in tests of methods defined by those types. But I'd change the way you did that a bit to avoid casting:
public class ServiceControllerImplTest {
ServiceController controller;
IDataChanged dataChangeListener;
#Before
public void setUp() {
instance = new ServiceControllerImpl();
controller = instance;
dataChangeListener = instance;
}
}

Mockito NotaMockException

I am facing an issue with Mockito junit testing. I am new to it and am a bit confused with the problem I am facing. Any help on this would be appreciated.
class Activity{
public void firstMethod(){
String str = secondMethod();
}
public String secondMethod(){
String str = null;
/* some Code */
return str;
}
}
Getting exception :
*org.mockito.exceptions.misusing.NotAMockException:
Argument passed to when() is not a mock!*
in the below code
class ActivityTest(){
Activity act;
#Before
public void setup(){
act = new Activity();
}
#Test
public void testFirstMethod(){
Mockito.doReturn(Mockito.anyString()).when(act).secondMethod();
act.firstMethod();
verify(act).secondMethod();
}
}
I am aware that activity is not a mock but I am not sure for a way around this as secondMethod() is a method in the same class. I need to write rule for secondMethod() as I have already done its Unit Testing. The definition of secondMethod() consists has external dependencies. Should I be mocking the external dependencies present in secondMethod() and writing rules for them rather than rule for secondMethod()?
I found this post:
Mockito Spy'ing on the object being unit tested
However separating the secondMethod() into a different class does not make sense. My method is related to this class. Creating a different class for testing does not seem right to me. Even mocking the actual class using spy() is not the most correct way as already explained in the post.
I don't think I should be creating a mock of the Activity class as that is the class I am testing. I would really appreciate help and insights into this.
As you noted, act is not a mock, and therefore you cannot record behavior on it. You could use Mockito.spy to, well, spy (or partially mock) the act object so that you only record the behavior of secondMethod and execute the actual code for firstMethod.
Note, however, that matchers can't be used in doReturn calls regardles of how you're mocking or spying your object. A return value must be a concrete object.
class ActivityTest() {
Activity act;
#Before
public void setup(){
act = Mockito.spy(new Activity()); // Here!
}
#Test
public void testFirstMethod(){
Mockito.doReturn("someString").when(act).secondMethod();
act.firstMethod();
verify(act).secondMethod();
}
}
A slightly more elegant syntax allows you to use annotations instead of explicitly calling Mockito.spy, but it's a matter of taste really:
#RunWith(MockitoJUnitRunner.class)
class ActivityTest() {
#Spy
Activity act = new Activity();
#Test
public void testFirstMethod(){
Mockito.doReturn("someString").when(act).secondMethod();
act.firstMethod();
verify(act).secondMethod();
}
}
There is no reason to mock anything in this example. Since there are no dependencies and both methods are public, you can test them directly.
public class ActivityTest() {
private Activity act = new Activity();
#Test
public void testSecondMethod(){
assertEquals("expected-value", act.secondMethod());
}
#Test
public void testFirstMethod() {
act.firstMethod();
// success if no exception occurs
}
}
Since firstMethod does not have any detectable effect on the Act instance, nor on any dependency (since there are none) you can simply call the method and be satisfied if no exception is thrown. One could also reason that such a method should not be tested at all.
I assume the example given is a simplification of a class where calling firstMethod actually does have side effects, who knows...
Here are some hints:
Mock the Activity.
Tweak the behavior of secondMethod with when / then / doReturn
Use doCallRealMethod when firstMethod is invoked.
Hope it helps.

How to unit-test in "tell, don't ask" follower classes?

I think the issue is explained best with an example.
public class MyService {
private OtherService theOther;
public void setTheOther(OtherService srv) { theOther = srv; }
public void myBusinessStuffFor(int id) {
theOther.applyToAllWith(id, new OtherService.Action() {
public void apply(Object whatever) {
doTheHardBusinessStuffWith(whatever);
}
}
}
private void doTheHardBusinessStuffWith(Object whatever) {
// here the business stuff provided by MyService
}
}
public interface OtherService {
void applyToAllWith(int id, Action action);
public interface Action {
void applyOn(Object whatever);
}
}
I like this pattern, because it's very cohesive. Action interfaces are paired with their Services. Business logic is not cluttered in many classes. Subclasses are only providing data to the action and don't have to be busy. I adopted it from here ( http://jamesladdcode.com/?p=12). The problem is that i didn't found a good solution for testing the behavior in the "doTheHardBusinessStuffWith(Object whatever)" method if i mock the otherService. With the mock i have to care how the business method gets called. But how can i do this. I use mockito and tried it with a ArgumentCapture already. But it don't feels right because of abusing ArgumentCapture.
I would like to know if the pattern used in class MyService.myBusinessStuffFor(int id) has a name (is it strategy pattern)?
But my major questions is how to make this code testable with mock of OtherService?
The other service is not really a business service in this case. Its only responsibility is to find the objects from the given ID, and apply the given action on these objects. Functionally, this is equivalent to the following code:
Set<Object> objects = otherService.getObjectsWithId(id);
for (Object o : objects) {
doTheHardBusinessStuffWith(o);
}
Make doTheHardBusinessStuffWith protected. Create a unit test for this method. This is the most important unit test: the one that tests the business logic.
If you really want to unit-test myBusinessStuffFor, what you could do is create a mock OtherService (and I mean implement this mock youself, here), that is built from a Set of objects, and applies its given action to all the objects in the set. Create a partial mock of MyService where the doTheHardBusinessStuffWith method is mocked, and which is injected with you mock OtherService. Call myBusinessStuffFor on the partial mock, and verify that doTheHardBusinessStuffWith has been called with every object of the set of objects.
You talk about mocking the OtherService. I don't know which mocking framework are you using; but you should be able to create a mock that just calls the applyOn method of the Action that gets passed to the applyToAllWith method, passing a mock object as the argument. In mockito, for example, this would be stubbed something like this.
doAnswer( new Answer<Object>(){
public Object answer( InvocationOnMock invocation ){
((Action) invocation.getArguments()[ 1 ]).applyOn( mockObject );
return null;
}}).when( mockOtherService ).applyToAllWith( anyInt(), any( Action.class ));
where mockOtherService is the mock you've created for the OtherService interface, and mockObject is whichever mock you want to pass to doTheBusinessHardStuffWith.

Categories

Resources