Issue 289 in mockito: Mock not injected into superclasses

2,089 views
Skip to first unread message

moc...@googlecode.com

unread,
Nov 2, 2011, 7:08:57 AM11/2/11
to mocki...@googlegroups.com
Status: New
Owner: ----
Labels: Type-Defect Priority-Medium

New issue 289 by m...@daniel-spilker.com: Mock not injected into
superclasses
http://code.google.com/p/mockito/issues/detail?id=289

What steps will reproduce the problem?

SomeService.java:

public class SomeService {
public void doSomething() {
}
}

AbstractSystemUnderTest.java:

import javax.inject.Inject;

public class AbstractSystemUnderTest {
@Inject
private SomeService someService;

public void doSomething() {
someService.doSomething();
}
}

import javax.inject.Inject;

SystemUnderTest.java:

public class SystemUnderTest extends AbstractSystemUnderTest {
@Inject
private SomeService someService;

public void doSomethingElse() {
someService.doSomething();
}
}

TheTest.java:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class TheTest {
@InjectMocks
private SystemUnderTest systemUnderTest;

@Mock
private SomeService someService;

@Test
public void someTest() {
systemUnderTest.doSomething();
}
}


What is the expected output? What do you see instead?

I would expect the test to succeed, but instead a NullPointerException is
thrown:

java.lang.NullPointerException
at AbstractSystemUnderTest.doSomething(AbstractSystemUnderTest.java:8)
at TheTest.someTest(TheTest.java:17)
...


What version of the product are you using? On what operating system?

I am using mockito-core 1.9.0-rc1

Please provide any additional information below.

The problem occurs only when a mock has to be injected in the class itself
and on one of its super classes. The injection algorithm seems to stop when
it found one field to inject for a given mock, but instead it should
continue to find matching fields in all super classes.

moc...@googlecode.com

unread,
Nov 2, 2011, 9:47:29 AM11/2/11
to mocki...@googlegroups.com
Updates:
Labels: -Type-Defect Type-Enhancement

Comment #1 on issue 289 by brice.du...@gmail.com: Mock not injected into
superclasses
http://code.google.com/p/mockito/issues/detail?id=289

This case wasn't on the roadmap, when coding this small injection utility.
This feature was never itnended to be a full featured injection framework.

Beside I think it's rather a wrong to have the very same field of the
parent class in a sub-type. You should really name it differently. Or maybe
event change the design with composition in mind instead of inheritance.

moc...@googlecode.com

unread,
Nov 2, 2011, 7:14:08 PM11/2/11
to mocki...@googlegroups.com

Comment #2 on issue 289 by szcze...@gmail.com: Mock not injected into
superclasses
http://code.google.com/p/mockito/issues/detail?id=289

Thanks for the report, Daniel

Is this a regression VS 1.8.5? E.g. was this test working for you with
Mockito 1.8.5?

As Brice says - the injection stuff in Mockito is simple - we're a mocking
framework and not a Guice =) If you need this feature please consider
contributing.

Cheers :)

moc...@googlecode.com

unread,
Nov 3, 2011, 4:53:43 AM11/3/11
to mocki...@googlegroups.com

Comment #3 on issue 289 by m...@daniel-spilker.com: Mock not injected into
superclasses
http://code.google.com/p/mockito/issues/detail?id=289

I just checkt and this is a regression vs. 1.8.5. indeed.

I like the simplicy of Mockito, no need to become a Guice or a Spring.

Before using @InjectMocks we had our own injection helper, which suffered
from the same problem. I will look into this and see if I can provide a
patch.

moc...@googlecode.com

unread,
Nov 3, 2011, 5:42:14 AM11/3/11
to mocki...@googlegroups.com

Comment #4 on issue 289 by brice.du...@gmail.com: Mock not injected into
superclasses
http://code.google.com/p/mockito/issues/detail?id=289

Oh, damn! I remember now, there's a piece of code that was added to avoid
injecting the dependency several times. This code was added during the
fixing for issue 236 because mockito was a bit too agressive at injecting
mocks.

Fixing this issue might require a clever way to inject things here and
there. No that this is bad thing, but Mockito tries to figure out by itself
types and fields at best and without configuration; it has no knowledge of
CDI/Spring/Guice annotations; and this choice has also some drawbacks.

Note however this part of the code will need revamp anyway to provide
configurable resolving mechanism.

moc...@googlecode.com

unread,
Nov 3, 2011, 6:05:29 AM11/3/11
to mocki...@googlegroups.com

Comment #5 on issue 289 by szcze...@gmail.com: Mock not injected into
superclasses
http://code.google.com/p/mockito/issues/detail?id=289

I think we should fix this regression before releasing 1.9.0. Thoughts?

moc...@googlecode.com

unread,
Nov 3, 2011, 6:29:40 AM11/3/11
to mocki...@googlegroups.com

Comment #6 on issue 289 by m...@daniel-spilker.com: Mock not injected into
superclasses
http://code.google.com/p/mockito/issues/detail?id=289

I created a simple patch. See the attachment. This patch simply considers
the whole set of mocks for injection into super classes. Currently only
mocks which have not already been injected are considered for super classes.

Attachments:
patch.txt 1.5 KB

moc...@googlecode.com

unread,
Nov 3, 2011, 6:57:56 AM11/3/11
to mocki...@googlegroups.com

Comment #7 on issue 289 by brice.du...@gmail.com: Mock not injected into
superclasses
http://code.google.com/p/mockito/issues/detail?id=289

Cool, you beat me there ;)

However if we do that, it means mocks can be injected more than once in the
instance then, but only once for a type in the hierarchy. I hope it won't
raise more issues.

In my opinion I think it is still weird to have a dependency injected two
times in a field with the same name.

moc...@googlecode.com

unread,
Dec 16, 2011, 4:39:58 PM12/16/11
to mocki...@googlegroups.com
Updates:
Status: Fixed
Labels: Milestone-Release1.9.0

Comment #8 on issue 289 by szcze...@gmail.com: Mock not injected into
superclasses
http://code.google.com/p/mockito/issues/detail?id=289

(No comment was entered for this change.)

moc...@googlecode.com

unread,
Dec 16, 2011, 5:28:30 PM12/16/11
to mocki...@googlegroups.com

Comment #9 on issue 289 by brice.du...@gmail.com: Mock not injected into
superclasses
http://code.google.com/p/mockito/issues/detail?id=289

Fixed in changeset f6aa67247b92

moc...@googlecode.com

unread,
Dec 16, 2011, 5:36:36 PM12/16/11
to mocki...@googlegroups.com

Comment #10 on issue 289 by brice.du...@gmail.com: Mock not injected into
superclasses
http://code.google.com/p/mockito/issues/detail?id=289

Fixed in revision f6aa67247b92

moc...@googlecode.com

unread,
Aug 24, 2012, 11:05:14 AM8/24/12
to mocki...@googlegroups.com

Comment #11 on issue 289 by pankajta...@gmail.com: Mock not injected into
superclasses
http://code.google.com/p/mockito/issues/detail?id=289

Hi,
I'm on 1.9.5-rc1 and I still see this issue.
The difference is when constructor injection happens in the class under
test, then the Mockito test runner does not traverse up the class heirarchy
to inject mocked collaborators.

I have two examples here. The first one (CarTest) works because the class
under test does not use an explicit constructor.
The second one (TruckTest) fails because it does.
The source is attached also.

First here is an abstract service:

public class AbstractService {
@Resource
protected PartsService partsService;
}

CarTest

The collaborators:
public class PartsService {
public String getPart(){
return "partA";
}
}
The class under test:
public class CarService extends AbstractService{
public void buildCar(){
String part = partsService.getPart();
System.out.println("Building car with part " + part);
}
}
The test:
@RunWith(MockitoJUnitRunner.class)
public class CarServiceTests {
@Mock private PartsService partsService;
@InjectMocks private CarService carService;
@Test
public void testBuildCarSimple(){
carService.buildCar();
}
}
This works fine.

Next:
TruckTest

First the collaborators:
public class TruckBodyPartService {
public String getBodyPart(){
return "bodyPart";
}
}
public class TruckEnginePartService {
public String getEnginePart(){
return "enginePart";
}
}
The class under test:
public class TruckService extends AbstractService {
private TruckEnginePartService truckEnginePartService;
private TruckBodyPartService truckBodyPartService;
public TruckService(TruckEnginePartService truckEnginePartService,
TruckBodyPartService truckBodyPartService){
this.truckEnginePartService = truckEnginePartService;
this.truckBodyPartService = truckBodyPartService;
}
public void buildTruck(){
partsService.getPart();
truckEnginePartService.getEnginePart();
truckBodyPartService.getBodyPart();
//Some testworthy biz logic
if (true){
System.out.println("built truck!");
}
}
}

Test:
@RunWith(MockitoJUnitRunner.class)
public class TruckServiceTests {
@Mock private PartsService partsService;
@Mock private TruckEnginePartService truckEnginePartService;
@Mock private TruckBodyPartService truckBodyPartService;
@InjectMocks private TruckService truckService;
@Test
public void testBuildTruck(){
truckService.buildTruck();
}
}

The above errors out with a NPE because partsService is not injected.

To fix I have to:

Add a setter to the parent class:
public class AbstractService {
@Resource
protected PartsService partsService;
public void setPartsService(PartsService partsService) {
this.partsService = partsService;
}
}

Then explicity call the setter in the test

@RunWith(MockitoJUnitRunner.class)
public class TruckServiceTests {
@Mock private PartsService partsService;
@Mock private TruckEnginePartService truckEnginePartService;
@Mock private TruckBodyPartService truckBodyPartService;
@InjectMocks private TruckService truckService;

@Test
public void testBuildTruck(){
truckService.setPartsService(partsService);
truckService.buildTruck();
}
}


So, I guess, this issue is still not resolved?

Thanks!
Pankaj





Attachments:
TestMockito.zip 6.7 KB

moc...@googlecode.com

unread,
Aug 24, 2012, 11:53:48 AM8/24/12
to mocki...@googlegroups.com

Comment #12 on issue 289 by brice.du...@gmail.com: Mock not injected into
superclasses
http://code.google.com/p/mockito/issues/detail?id=289

Hi,

This issue has been resolved for setter/field injection.

"The difference is when constructor injection happens in the class under
test, then the Mockito test runner does not traverse up the class heirarchy
to inject mocked collaborators."

Tis behavior is expected for constructor injection, Mockito will see this
class as initialized, as it should be when programming correct object
oriented code.

This snippet looks wrong in OO style :
TruckService truckService = new TruckService(enginePartsService,
bodyPartsService);
truckService.setPartsService(partsService);


Plus if mockito takes this decision alone after using the constructor it
have more chance to break what the constructor might have initialized, as
mockito can't detect this, we chose the safest option. Also we have no
knowledge of other frameworks annotations such as @Inject, @Resource,
@Autowied, etc.

In the end this behavior will not change for constructor injection.

If you want injection to happen correctly write a constructor that will
require all the dependencies your object will need, something like :

public class AbstractService {
protected AbstractService(PartsService partsService) {
this.partsService = partsService;
}
}

public class TruckService extends AbstractService {
public TruckService(PartsService partsService, TruckEnginePartService
truckEnginePartService, TruckBodyPartService truckBodyPartService) {
super(partsService)
this.truckEnginePartService = truckEnginePartService;
this.truckBodyPartService = truckBodyPartService;
}
}

Cheers
Brice

moc...@googlecode.com

unread,
Aug 24, 2012, 12:32:44 PM8/24/12
to mocki...@googlegroups.com

Comment #13 on issue 289 by pankajta...@gmail.com: Mock not injected into
superclasses
http://code.google.com/p/mockito/issues/detail?id=289

I see what you mean. I will implement your suggestion.
Thanks!

moc...@googlecode.com

unread,
Aug 24, 2012, 12:39:18 PM8/24/12
to mocki...@googlegroups.com

Comment #14 on issue 289 by brice.du...@gmail.com: Mock not injected into
superclasses
http://code.google.com/p/mockito/issues/detail?id=289

You are welcome :)

Also, you might be interested to read the Growing Object Oriented Software
book (and their mailing-list), the content is great.

Cheers,
Brice


Reply all
Reply to author
Forward
0 new messages