easyforgood / mockito

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

NullPointerException due to uninitialized final fields when mocked #408

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
What steps will reproduce the problem?

1. Write a simple abstract class with some final field that is initialized at 
the time of declaration
2. Write a test in which the above class is marked with @Mock
3. In the test, call MockitoAnnotations.initMocks(this), and just print the 
value of the final field in question.

Here's an example of the complete test class to reproduce this:

import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

public class FinalFieldUninitializedInMockTest {

    public static abstract class TestFinalField {

        private final StringBuffer someValue = new StringBuffer("Testing Mockito");

        public abstract void dumbMethod();

        public String getTheString() {
            return someValue.toString();
        }
    }

    @Mock
    TestFinalField mockOfTestFinalField;

    @Test
    public void theTest() {
        MockitoAnnotations.initMocks(this);
        System.out.println(mockOfTestFinalField.someValue);
    }
}

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

Expected output of the above test is that it prints "Testing Mockito". However, 
in actuality, the someValue is never initialized to its declared value, so the 
output is "null" instead.

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

I'm using mockito-all-1.8.5 on a Linux environment with JDK 1.6 (jdk1.6.0-u37 I 
think)

Please provide any additional information below.

- Not sure if this is a bug, or I'm missing something, so please excuse my 
ignorance if that be the case!
- Also, I have a slight feeling the current behavior might be related with  
what Issue no. 242 talks about.

Original issue reported on code.google.com by anu.glob...@gmail.com on 28 Dec 2012 at 4:38

GoogleCodeExporter commented 8 years ago
Hi,

Actually this is expected, this is a side effect of the way Objenesis is using 
JVM internals to instantiate our generated classes. As Objenesis uses tricks 
that bypasses default constructor in order to create an instance of an object.

This is necessary to create mock instances. ANd it shouldn't be an issue for 
standard mock as mock are about interactions with methods not fields.

However that being said for partial mocks it might be an issue if someone 
intends to use real method.

Note that not only final fields are affected but all fields that have a non 
default value.

I'm sorry but I don't think there is a way to instantiate a proxy class, while 
still executing the class init constructor. So I will set this issue to WontFix.
If you have a known way to perform such I'd be happy to know how to do it, talk 
to the guys at Objenesis.

Cheers,
Brice

Original comment by brice.du...@gmail.com on 3 Jan 2013 at 11:09

GoogleCodeExporter commented 8 years ago
Thanks for the detailed explanation.

I understand the constraints, and there is I believe a workaround that
involves reflection.

But, like you mention, if mockito/objenesis uses dynamic way of creating
mocks via proxy classes, I agree reflection would be possible to do within
the mockito framework - it'd have to be written in the test itself.

I discovered this when a test started failing due to a dependency on an
abstract class with a final field *and* a final method, which forced a
partial mock strategy to be used.

Original comment by anu.glob...@gmail.com on 3 Jan 2013 at 9:04

GoogleCodeExporter commented 8 years ago
Correction: "...I agree reflection would *NOT *be possible to do within the
mockito framework...

Original comment by anu.glob...@gmail.com on 3 Jan 2013 at 9:06