I'm trying to unit test my Presenter class using Mockito and I always end up failing the test:
org.mockito.exceptions.base.MockitoException:
Cannot mock/spy class java.lang.String
Mockito cannot mock/spy following:
- final classes
- anonymous classes
- primitive types
This is what my Presenter class looks like:
public class EditorPresenter implements EditorContract.Presenter {
private DataSource dataSourceImpl;
private EditorContract.View mView;
private SharedPreferences prefs;
EditorPresenter(SharedPreferences prefs,
DataSourceImpl dataSourceImpl,
EditorContract.View mView) {
this.dataSourceImpl = dataSourceImpl;
this.mView = mView;
this.prefs = prefs;
mView.setPresenter(this);
}
@Override
public void showNewNote() {
String noteColor = prefs.getString("default_note_color", "#ef5350");
String textColor = prefs.getString("default_text_color", "#000000");
mView.noteColor(Color.parseColor(noteColor));
mView.textColor(Color.parseColor(textColor));
}
}
And this is what I've done so far in EditorPresenterTest class:
public class EditorPresenterTest {
@Mock
private EditorContract.View mView;
@Mock
private DataSourceImpl mDataSourceImpl;
@Mock
private SharedPreferences sharedPrefs;
@Mock
private String noteColor;
@Mock
private String textColor;
@Before
public void setUpEditorPresenter() {
MockitoAnnotations.initMocks(this);
}
@Test
public void createEditorPresenter_newNote() {
EditorPresenter editorPresenter = new EditorPresenter(
sharedPrefs,
mDataSourceImpl,
mView);
verify(mView).setPresenter(editorPresenter);
}
@Test
public void showNewNote() {
when(sharedPrefs.getString(eq("default_note_color"), eq("#ef5350"))).thenReturn(noteColor);
when(sharedPrefs.getString(eq("default_text_color"), eq("#000000"))).thenReturn(textColor);
verify(mView).textColor(Color.parseColor(noteColor));
verify(mView).noteColor(Color.parseColor(textColor));
}
(Note: I'm new to Mockito and testing)
I have passed the createEditorPresenter_newNote()
but the showNewNote()
failed the test and shows error. Any Feedback/Answers are welcome. Hope someone helps me. Thanks!
I will first answer the exact question that you asked here but keep in mind that you have a larger issue that is hiding behind your compilation error, for which I will provide an answer right after. (please keep in mind that I have no real experience with Android, so exact class names and use cases might not be valid, but your issues are more with understanding what test frameworks do and not syntax-oriented).
Your first issue is that you are trying to create mock types of the String class, which is final. As you can see in the error from Mockito:
Mockito cannot mock/spy following:
- final classes
In essence, there is no real reason for creating a mock of a String, because you are not testing String functionality. You can just use a constant.
if that is what you wish to fix, just remove the @Mock
annotations from the noteColor
and textColor
variables and initialize them with some constant values.
There is another major issue in your test case, and that is that you are trying to use the EditorPresenter
you created in the first test inside the scope of the second test.
The thing is that test frameworks run different tests in separate states (rightfully so). So when you create the EditorPresenter
instance inside the createEditorPresenter_newNote
method, it won't be visible for you in the showNewNote
test method, because it is a different process (not a different CPU process - just a process in the simple day-to-day term of the word).
That's what the before
method is for: it will be called before every test runs, so you can set up shared functionality in one place.
what you should be doing is more on the line of this:
public class EditorPresenterTest {
@Mock
private EditorContract.View mView;
@Mock
private DataSourceImpl mDataSourceImpl;
@Mock
private SharedPreferences sharedPrefs;
private EditorPresenter editorPresenter;
@Before
public void setUpEditorPresenter() {
MockitoAnnotations.initMocks(this);
this.editorPresenter = new EditorPresenter(
sharedPrefs,
mDataSourceImpl,
mView);
}
@Test
public void createEditorPresenter_newNote() {
verify(mView).setPresenter(editorPresenter);
}
@Test
public void showNewNote() {
editorPresenter.showNewNote();
String noteColor = "#ef5350"; // or whatever color you want
String textColor = "#000000"; // or whatever color you want
when(sharedPrefs.getString(eq("default_note_color"), eq("#ef5350"))).thenReturn(noteColor);
when(sharedPrefs.getString(eq("default_text_color"), eq("#000000"))).thenReturn(textColor);
verify(mView).textColor(Color.parseColor(noteColor));
verify(mView).noteColor(Color.parseColor(textColor));
}
}