I write unit test for my Presenter, which is need to mock my Local Data Source.
Here is my simple test :
public class AddressPresenterTest {
@Mock
private AddressView mView;
@Mock
private AddressDataSource mDataSource;
@Mock
private AddressLocalDataSource mLocalDataSource;
@Captor
ArgumentCaptor<DataSourceCallback<Province>> mProvinceCallbackCaptor;
private AddressPresenter mPresenter;
@Before
public void beforeTest() {
MockitoAnnotations.initMocks(this);
mPresenter = new AddressPresenter(mDataSource, mView);
mPresenter.setLocalDataSource(mLocalDataSource);
}
@Test
public void When_SelectProvince_DataIsNull_ShowErrorMessage() {
mPresenter.getLocalProvinceById(2129023);
// Cause data source has callback, we need to capture the callback
ArgumentCaptor<Integer> provinceIdCaptor = ArgumentCaptor.forClass(Integer.class);
verify(mLocalDataSource).fetchProvinceById(provinceIdCaptor.capture(), mProvinceCallbackCaptor.capture());
mProvinceCallbackCaptor.getValue().onFailedLoad();
verify(mView).loadContentError();
}
}
When i run this test i got the error,
org.mockito.exceptions.base.MockitoException:
Mockito cannot mock this class: class com.dai.uangteman.data.AddressLocalDataSource.
Mockito can only mock non-private & non-final classes.
If you're not sure why you're getting this error, please report to the mailing list.
Java : 1.8
JVM vendor name : Oracle Corporation
JVM vendor version : 25.77-b03
JVM name : Java HotSpot(TM) 64-Bit Server VM
JVM version : 1.8.0_77-b03
JVM info : mixed mode
OS name : Mac OS X
OS version : 10.12.6
Underlying exception : java.lang.IllegalArgumentException: Could not create type
at com.dai.uangteman.view.fragment.presenter.AddressPresenterTest.beforeTest(AddressPresenterTest.java:41)
...
Caused by: java.lang.IllegalArgumentException: Could not create type
at net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:140)
... 28 more
Caused by: java.lang.NoClassDefFoundError: android/database/sqlite/SQLiteOpenHelper
at java.lang.ClassLoader.defineClass1(Native Method)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:138)
... 45 more
Caused by: java.lang.ClassNotFoundException: android.database.sqlite.SQLiteOpenHelper
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
... 87 more
When i workaround to change my AddressLocalDataSource
class i found something weird.
public class AddressLocalDataSource {
private StaticDatabaseHelper mDatabaseHelper;
// /**
// * @param mDatabaseHelper
// */
// public AddressLocalDataSource(StaticDatabaseHelper mDatabaseHelper) {
// this.mDatabaseHelper = mDatabaseHelper;
// }
public void setDatabaseHelper(StaticDatabaseHelper mDatabaseHelper) {
this.mDatabaseHelper = mDatabaseHelper;
}
...
}
Below what i found :
- I try to remove my constructor and setter method which is contain
StaticDatabaseHelper
object parameter and it works! - I try to change the
StaticDatabaseHelper
initialization in setter method it doesn't work!
The problem is my AddressLocalDataSource
need instance of StaticDatabaseHelper
class.
Any idea? thank you
Seems you also need to mock StaticDatabaseHelper. Then Mockito should automatically inject your mocked instance into the AddressLocalDataSource. So adding following line may solves your issue:
After a couple hour i looking for solution, i get the simplest solution. I think there is some incomplete in android library for testing. So i just run this gradle command to cleanup :
And it works now, i just mock
StaticDatabaseHelper
class in this case. So this is my final testing Class :Hope this help, thank you
In my case, in my project using javassist-3.11.0.GA.jar. After google some papers talk about the issue above related to javassist verison so I try to upgrade javassist to javassist-3.18.2-GA.jar or javassist-3.21.0-GA.jar the issue is resolved.
Some others issues can resolve by this way as below:
,
,
Regards,