wujun / powermock

Automatically exported from code.google.com/p/powermock
Apache License 2.0
0 stars 0 forks source link

Mockito; mock name in @Mock(name="abc") annotatioins ignored #423

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?
1. Declare two mocks of the same interface:
  @Mock(name="abc")
  SomeInterface mock1;
  @Mock(name="def")
  SomeInterface mock2;
2. Declare the tested object to inject the mocks into:
  @InjectMocks
  SomeService service = new SomeServiceImpl();
3. Related SomeServiceImpl details:
  public class SomeServiceImpl {
    private SomeInterface abc;
    private SomeInterface def;
    ...
  }

What is the expected output? What do you see instead?
  Expected: service.abc != null && service.def != null
  Actual: service.abc == null && service.def == null

What version of the product are you using? On what operating system?
  Tried both mockito-1.8.5 + powermock 1.4.10 and mockito-1.9.5 + powermock 1.5.

Please provide any additional information below.
  By debugging it was resolved that the mock names of both mock1 and mock2 are both "someInterface" instead of "abc" and "def" respectively. It appears PowerMock does not consider the "name" parameter of the @Mock mockito annotation at all.

  When trying to find out why, I bumped into the following potential show-stoppers:
  1. AnnotationEnabler.standardInject() calls PowerMockito.mock(Class) instead of PowerMockito.mock(Class, MockSettings) and using MockSettings.name() to set the name. Please see mockito-1.9.5 / MockAnnotationProcessor.process() for how mockito handles naming of mocks.

  2. MockCreator.mock() ignores any name set in the mockSettings argument and instead creates a name based on the field type (and updates the given mockSettings with it).

Due to the second point, when using PowerMockit.mock(Class, MockSettings) with 
a mock name set in the settings argument it would thus also be ignored.

As a workaround to this problem I invented the following: Since the @Mock:ed 
field type is used for the mock name, and the mock name is used when matching 
against names of fields in the SomeServiceImpl class, I can create fake 
interfaces used only in testing named suitably, e.g.

  public interface Abc extends SomeInterface {}
  public interface Def extends SomeInterface {}

  @Mock
  Abc mock1;
  @Mock
  Def mock2;

Please note that SomeServiceImpl is untouched. Now mock1 gets injected into 
field "abc" and mock2 to "def" as wanted. The Abc and Def interfaces need only 
be visible to test code, so it does not pollute the actual code in any way.

The workaround works for classes as well as long as they are not final.

Original issue reported on code.google.com by jonas.be...@nitorcreations.com on 17 Jan 2013 at 12:21

GoogleCodeExporter commented 9 years ago
Also please note that the default Mockito behaviour of using field name as 
default mock name (when an explicit @Mock(name="xyz") has not been given) does 
not work either as PowerMockito instead uses the field type as base for default 
mock name:

  @Mock
  SomeInterface abc;
  @Mock
  SomeInterface def;

The referred mockito-1.9.5 / MockAnnotationProcessor.process() implements this 
aspect as well.

Original comment by jonas.be...@nitorcreations.com on 17 Jan 2013 at 1:16

GoogleCodeExporter commented 9 years ago
It could be that org.powermock.api.extension.listener.AnnotationEnabler is not 
updated to reflect the latest Mockito changes. If you want to help out you're 
very welcome.

Original comment by johan.ha...@gmail.com on 22 Jan 2013 at 7:53