mlinhard / mockito

Automatically exported from code.google.com/p/mockito
0 stars 0 forks source link

Problem with mocking not overriden method which uses generics #500

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?
1. Create classes:
abstract class AbstractConverter<F, T> {

    public List<T> convert(List<F> from) {
        List<T> result = new ArrayList<>();
        for (F f : from) {
            result.add(convert(f));
        }
        return result;
    }

    public abstract T convert(F from);
}

public class ConcreteConverter extends AbstractConverter<Integer, String> {

    @Override
    public String convert(Integer from) {
        return from.toString();
    }
}
2. Create Test:
@RunWith(MockitoJUnitRunner.class)
public class MyTest {

    @Mock
    private ConcreteConverter cc;

    @Mock
    private List<Integer> intList;

    @Mock
    private List<String> stringList;

    @Test
    public void test() {
        when(cc.convert(intList)).thenReturn(stringList);
    }
}
3. Run the test.

What is the expected output? What do you see instead?
The test should run flawlessly but instead it fails with NullPointerException. 
It seems that object cc is not mocked correctly because method convert is 
invoked.

What version of the product are you using? On what operating system?
<dependency>
  <groupId>org.mockito</groupId>
  <artifactId>mockito-core</artifactId>
  <version>1.9.5</version>
  <scope>test</scope>
</dependency>
Centos 6.3
java version "1.7.0_65"
OpenJDK Runtime Environment (rhel-2.5.1.2.el6_5-x86_64 u65-b17)
OpenJDK 64-Bit Server VM (build 24.65-b04, mixed mode)

Please provide any additional information below.
The problem can be bypassed by mocking class:
private static class MyConverter extends ConcreteConverter {

    @Override
    public List<String> convert(List<Integer> ints) {
        return super.convert(ints);
    }
}
instead of ConcreteConverter class

Original issue reported on code.google.com by arkadius...@gmail.com on 8 Aug 2014 at 6:54

GoogleCodeExporter commented 9 years ago
I just copied this all to a project, except for changing "MyTest" to 
"ConcreteConverterTest" and adding required imports.  I ran it from the command 
line and Eclipse with JDK 1.7.0_51.  In both cases it ran without error.

I'm running on Win7.

Perhaps you should run this in the debugger and see if you can see any other 
clues?

Original comment by davidmic...@gmail.com on 8 Aug 2014 at 3:15

GoogleCodeExporter commented 9 years ago
This case is even more complicated than I thought. Three classes have to be 
declared in three different compilation units (three different files) and 
AbstractConverter need to have default visibility.

All classes can be declared in one package (even in default package).

Original comment by arkadius...@gmail.com on 11 Aug 2014 at 6:39

GoogleCodeExporter commented 9 years ago
[deleted comment]
GoogleCodeExporter commented 9 years ago
This bug is really similar to next issue: #434. Please take a look into byte 
code:

public class org.mockito.ConcreteConverterTest {
  public org.mockito.ConcreteConverterTest();
    Code:
       0: aload_0       
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return        

  public void test();
    Code:
       0: aload_0       
       1: getfield      #2                  // Field cc:Lorg/mockito/ConcreteConverter;
       4: aload_0       
       5: getfield      #3                  // Field intList:Ljava/util/List;
       8: invokevirtual #4                  // Method org/mockito/ConcreteConverter.convert:(Ljava/util/List;)Ljava/util/List;
      11: invokestatic  #5                  // Method org/mockito/Mockito.when:(Ljava/lang/Object;)Lorg/mockito/stubbing/OngoingStubbing;
      14: aload_0       
      15: getfield      #6                  // Field stringList:Ljava/util/List;
      18: invokeinterface #7,  2            // InterfaceMethod org/mockito/stubbing/OngoingStubbing.thenReturn:(Ljava/lang/Object;)Lorg/mockito/stubbing/OngoingStubbing;
      23: pop           
      24: return        
}

public class org.mockito.ConcreteConverter extends 
org.mockito.AbstractConverter<java.lang.Integer, java.lang.String> {
  public org.mockito.ConcreteConverter();
    Code:
       0: aload_0       
       1: invokespecial #1                  // Method org/mockito/AbstractConverter."<init>":()V
       4: return        

  public java.lang.String convert(java.lang.Integer);
    Code:
       0: aload_1       
       1: invokevirtual #2                  // Method java/lang/Integer.toString:()Ljava/lang/String;
       4: areturn       

  public java.lang.Object convert(java.lang.Object);
    Code:
       0: aload_0       
       1: aload_1       
       2: checkcast     #3                  // class java/lang/Integer
       5: invokevirtual #4                  // Method convert:(Ljava/lang/Integer;)Ljava/lang/String;
       8: areturn       

  public java.util.List convert(java.util.List);
    Code:
       0: aload_0       
       1: aload_1       
       2: invokespecial #5                  // Method org/mockito/AbstractConverter.convert:(Ljava/util/List;)Ljava/util/List;
       5: areturn       
}

It is not easy to solve this problem. I will take a deeper look later when I 
find some time and get to know changes in the project. Btw. I think that in 
future it is better idea just to create issue on github: 
https://github.com/mockito/mockito

Original comment by albers...@gmail.com on 18 Aug 2014 at 10:04

GoogleCodeExporter commented 9 years ago
Thank you for feedback. I will try to remember to create new issues on github 
(here I have got great issue number ;-))

Original comment by arkadius...@gmail.com on 19 Aug 2014 at 5:10