Mockito test in MVP pattern - java

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.
More about testing frameworks and the other problems you are facing:
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).
What should you be doing instead?
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));
}
}

Related

Mock new objects in empty constructor

I am currently working on a AWS Lambda using Java 11. It is requiring me for an implementation of the handler to have an empty constructor. My handler looks like this
public class ApiKeyHandler {
private final SecretsManagerClient secretsManagerClient;
public ApiKeyHandler() {
secretsManagerClient = DependencyFactory.secretsManagerClient();
}
public void handleRequest(Object event, Context context) {
//Other codes here
secretsManagerClient.getSecret(/../);
}
}
And Dependency Factory class
public class DependencyFactory {
private DependencyFactory() {}
/**
* #return an instance of SecretsManagerClient
*/
public static SecretsManagerClient secretsManagerClient() {
return SecretsManagerClient.builder()
.region(/**/)
.build();
}
}
Now, when I am trying to write unit test for this I cant mock objects in constructor. Is there a way I can mock it?
I tried
#Mock SecretsManagerClient secretsManagerClient;
#InjectMocks ApiKeyHandler handler;
but no luck. Thank you
It looks like you have a couple of options:
You can add another constructor with the parameters to inject. This is easy and clean from the test perspective, but after all you'll have the code in production (this constructor in this case) that is used only for tests.
In generally I don't advocate this approach, although I understand that there are technology limitations here.
You can Mock the Dependency Factory. Since the call is static, you might end up using PowerMock / PowerMockito that can actually mock static calls. This is something that can turn to be really painful to maintain, in general this approach is discouraged these days.
You can Rewrite the DependencyFactory so that it could be configured with some kind of mock implementation (that will allow to specify mock dependencies):
public interface DependencyFactoryMode {
SecretsManagerClient secretsManagerClient();
}
public class RealDependencyFactoryMode implements DependencyFactoryMode {
public SecretsManagerClient secretsManagerClient() {
return SecretsManagerClient.builder()
.region(/**/)
.build();
}
}
// in src/test/java - test code in short
public class DependencyFactoryTestMode implements DependencyFactoryMode {
private SecretsManagerClient smc = Mockito.mock(SecretsManagerClient.class);
public SecretsManagerClient secretsManagerClient() {
return smc;
}
// this will be used in tests
public SecretsManagerClient getSmcMock() {return smc;}
}
public class DependencyFactory {
private static DependencyFactoryMode mode;
static {
// depending on the configuration, external properties or whatever
// initialize in production mode or test mode
// of course this is the most "primitive" implementation you can probably
// do better
if(isTest) {
mode = new TestDependencyFactoryTestMode();
} else {
// this is a default behavior
mode = new RealDependencyFactoryMode();
}
}
private DependencyFactory() {}
public static DependencyFactoryMode getMode() {
return mode;
}
public static SecretsManagerClient secretsManagerClient() {
return mode.secretsManagerClient();
}
}
With this approach you'll have to pre-configure the dependency factory so that while running in the test it will "know" that it should run in the test mode.
public class Test {
#Test
public void test() {
// DependencyFactoryMode will be used in the test mode
DependecyFactoryMode testMode = DependencyFactory.getMode();
var smc = testMode.secretsManagerClient();
Mockito.when(smc.foo()).thenReturn(...);
}
}
Now this approach suffers from the same drawback as "1" but at least you have a code "only for tests" only in the factory, rather than in all lambda functions (I assume you have many of them, otherwise probably the first approach will be the least of all evils).
Another possible drawback is that the same instance of DependencyFactory (with the shared static mocking mode) will be shared between the tests, so you might end up "reseting" all the relevant mocks after the test.
Again, these all are complications because in the form that you've presented there is no way to provide a dependency injection in constructor because of the technology limitation.
Add a second constructor that accepts parameters:
public ApiKeyHandler(SecretsManagerClient client) {
secretsManagerClient = client;
}
public ApiKeyHandler() {
this(DependencyFactory.secretsManagerClient());
}

Best Practices for Unit Testing Builder Objects?

There is great debate about whether or not setters/getters should be unit tested.
Example
Should unit tests be written for getter and setters?
I believe that builder objects fall within the same conversation. I want to know best practices for unit testing a builder object. Here are my thoughts.
i. confirm that builder object can be created
ii. confirm that output reflects input
iii. confirm that omitted constructs will throw exception (if they are required)
Additionally, if the builder object is required for instantiating another object, does it make sense to also create a test to confirm that the second object instantiates with given builder? Any critiques on what I am missing or should omit is appreciated.
#RunWith(AndroidJUnit4.class)
public class MyBuilderTest {
private Context mContext;
private ApiClient mApiClient;
private Profile mProfileBuilder;
private ProfilePojo mProfileSampleResponse;
#Before
public void setUp() {
mContext = InstrumentationRegistry.getTargetContext();
mProfileSampleResponse= new Gson().fromJson(Utils.getLocalJsonFile(mContext,
R.raw.profile_info), ProfilePojo.class);
}
#Test
public void checkLocalProfileResponse() {
assertNotNull(mProfileSampleResponse);
}
#Test
public void checkProfileBuilder() {
mProfileBuilder = new Profile.ProfileBuilder()
.setFirstName(mProfileSampleResponse.firstName)
.setLastName(mProfileSampleResponse.lastName)
.isVerified(mProfileSampleResponse.isVerified)
.create();
assertNotNull(mProfileBuilder);
assertNotNull(mProfileBuilder.getFirstName());
assertNotNull(mProfileBuilder.getLastName());
assertEquals(mProfileSampleResponse.isVerified, mProfileBuilder.getIsVerified);
assertEquals(mProfileSampleResponse.firstName, mProfileBuilder.getFirstName);
assertEquals(mProfileSampleResponse.lastName, mProfileBuilder.getLastName);
}
#Test
public void checkApiClientBuilder() {
mApiClient= new ApiClient(mContext, mProfileBuilder);
assertNotNull(mApiClient);
}
}
In my case, I also need to test request and responses. The profile information I build with the ProfileBuilder can be passed into the ApiClient and the ApiClient will make request for me. Should all of this be inside of one test class?

Spring boot Unit test about best practics and currectli writing tests

I want start write unit test in my project. I tried make this many times. And he always quit, because he could not understand the meaning. because I can not find and form knowledge into a single whole. I read many articles, saw many examples, and they are all different. As a result, I understand why I need write tests, I understand how to write them, but I do not understand how correctly. And I do not understand how to write them so that they are useful. I have some questions:
For example I have service:
#Service
public class HumanServiceImpl implements HumanService {
private final HumanRepository humanRepository;
#Autowired
public HumanServiceImpl(HumanRepository humanRepository) {
this.humanRepository = humanRepository;
}
#Override
public Human getOneHumanById(Long id) {
return humanRepository.getOne(id);
}
#Override
public Human getOneHumanByName(String firstName) {
return humanRepository.findOneByFirstName(firstName);
}
#Override
public Human getOneHumanRandom() {
Human human = new Human();
human.setId(Long.parseLong(String.valueOf(new Random(100))));
human.setFirstName("firstName"+ System.currentTimeMillis());
human.setLastName("LastName"+ System.currentTimeMillis());
human.setAge(12);//any logic for create Human
return human;
}
}
And I tried write Unit test for this service:
#RunWith(SpringRunner.class)
public class HumanServiceImplTest {
#MockBean(name="mokHumanRepository")
private HumanRepository humanRepository;
#MockBean(name = "mockHumanService")
private HumanService humanService;
#Before
public void setup() {
Human human = new Human();
human.setId(1L);
human.setFirstName("Bill");
human.setLastName("Gates");
human.setAge(50);
when(humanRepository.getOne(1L)).thenReturn(human);
when(humanRepository.findOneByFirstName("Bill")).thenReturn(human);
}
#Test
public void getOneHumanById() {
Human found = humanService.getOneHumanById(1L);
assertThat(found.getFirstName()).isEqualTo("Bill");
}
#Test
public void getOneHumanByName() {
Human found = humanService.getOneHumanByName("Bill");
assertThat(found.getFirstName()).isEqualTo("Bill");
}
#Test
public void getOneHumanRandom() {
//???
}
}
I have questions:
1. Where should I fill the objects? I saw different implementations
in #Before like in my example, in #Test, mix implementations - when Human create in #Before and expression
when(humanRepository.getOne(1L)).thenReturn(human);
in #Test method
private Human human;
#Before
public void setup() {
human = new Human();
...
}
#Test
public void getOneHumanById() {
when(humanRepository.getOne(1L)).thenReturn(human);
Human found = humanService.getOneHumanById(1L);
assertThat(found.getFirstName()).isEqualTo("Bill");
}
2. How can I test getOneHumanRandom() method?
Service not use repository when call this method. I can make this method mock, but what will it give?
when(humanService.getOneHumanRandom()).thenReturn(human);
...
#Test
public void getOneHumanRandom() {
Human found = humanService.getOneHumanRandom();
assertThat(found.getFirstName()).isEqualTo("Bill");
}
I just copy the logic from the service in the test class. What is the point of such testing and is it necessary?
1. Where should I fill the objects? I saw different implementations
I would use #Before for any common setup between all / most tests. Any setup that is specific to a certain test should be go into that test method. If there is a common setup between some, but not all, of your tests you can write private setup method(s).
Remember to keep your tests / code DRY (dont repeat yourself!). Tests have a maintenance factor and keeping common code together with help alleviate some headaches in the future.
2. How can I test getOneHumanRandom() method?
You should create a Human toString() method. This method should concat all the properties on your Human object. You can call getOneHumanRandom() twice and assert that they are not equal.
#Test
public void getOneHumanRandomTest()
{
// SETUP / TEST
Human one = service.getOneHumanRandom();
Human two = service.getOneHumanRandom();
// VERIFY / ASSERT
assertNotEquals("these two objects should not be equal", one.toString(), two.toString())
}
Hope this helps!

Using factory method for creating common Mockito stubbings in Java

In project I am working on we have a bunch of commonly used helpers. Consider the following example:
public class ServiceHelper {
public HttpServletRequest() getRequest() { ... }
public Model getModel() { ... }
public UserCache getUserCache() { ... }
public ComponentContainer getComponentContainer() { ... }
}
Imagine this helper is being used across the whole application by every web service we have. Then, in order to test these services I need to mock it. Each time. But what if I create a factory of some kind instead, something like:
public class ServiceHelperMockStore {
public static ServiceHelper create() {
return init();
}
public static ServiceHelper create(final Model model) {
final ServiceHelper helper = init();
when(helper.getModel()).thenReturn(model);
return helper;
}
private static ServiceHelper init() {
final ServiceHelper helper = mock(ServiceHelper.class);
final HttpServletRequest request = mock(HttpServletRequest.class);
final Model model = mock(Model.class);
final UserCache userCache = mock(UserCache.class);
final ComponentContainer container = mock(ComponentContainer.class);
final BusinessRules businessRules= mock(BusinessRules.class);
final ModelTransformer modelTransformer = mock(ModelTransformer.class);
when(helper.getRequest()).thenReturn(request);
when(helper.getModel()).thenReturn(model);
when(helper.getUserCache()).thenReturn(userCache);
when(helper.getComponentContainer()).thenReturn(container);
when(container.getComponent(BusinessRules.class)).thenReturn(businessRules);
when(componentContainer.getComponent(ModelTransformer.class)).thenReturn(modelTransformer);
return helper;
}
}
This factory nicely fit my purposes and oftentimes I can completely avoid using 'mock' and 'when' in the actual test suites. Instead, I can do the following:
#RunWith(MockitoJUnitRunner.Silent.class)
public class ModelServiceTest {
private final Model model = new Model();
private final ServiceHelper serviceHelper = ServiceHelperMockStore.create(model);
private final BusinessRules businessRules = serviceHelper.getComponentContainer().getComponent(BusinessRules.class);
private final ModelType modelType1 = new ModelType();
private final ModelType modelType2 = new ModelType();
private final ModelService modelService = new ModelService(serviceHelper);
#Before
public void setUp() {
modelType1.setItemId("item1");
modelType2.setItemId("item2");
model.setTypes(modelType1, modelType2);
when(businessRules.get("type")).thenReturn(modelType1);
}
...tests...
}
So instead of creating a lot of mocks in the ModelServiceTest, I can just access the predefined ones, like:
BusinessRules businessRules = serviceHelper.getComponentContainer().getComponent(BusinessRules.class);
and this even reflect my helper's API. Also, I can provide my own mock or stub passing parameters to my factory method or using some different approach.
The only problem I have is UnnecessaryStubbingException being thrown by Mockito as normally I don't use all those stubbings I've created per each test file. So I have to use MockitoJUnitRunner.Silent runner to silent the error and according to the mockito api docs it is not recommended.
So I am seeking for an advice what kind of approach must be chosen in this case. Am I doing it right or there is some other way? Or, maybe, using such kind of factories is a bad style of programming in relation to unit tests as it hides some initialization and makes happening things less evident so I must do just a plain copy of my code between test suits?
The fact that you need this identical complex mock configuration at different places shows that your code violates the Law of Demeter (Don't talk to strangers).
A unit should only get dependencies it actually interacts with (other than only to getting another dependency from it).
So instead of creating a lot of mocks in the ModelServiceTest, I can just access the predefined ones,
You Unittests are not only verification of correct behavior but also minimal examples how to use the CUT (Code under test).
The configuration of the CUTs dependencies is an essential part of that example and should be easily accessible to the reader of the tests.
I'd strongly discourage from "factories for mocks" especially it they were moved to other classes (in the test folder).

junit test for methods calling another method of different class

I am writing Junit test for the below code using Mockito but I am getting a null pointer exception is there a mistake in the way I'm mocking it?
public boolean isApplyChecked()
{
return _rranalysis.getApplytoAllState();
}
and my test case is
#Test
public void testIsApplyChecked() {
JCheckBox Rra_Apply_Field = Mockito.mock(JCheckBox.class);
Mockito.when(Rra_Apply_Field.isSelected()).thenReturn(true);
RepeatRejectAnalysis rs = Mockito.mock(RepeatRejectAnalysis.class);
Mockito.when(rs.getApplytoAllState()).thenReturn(true);
boolean val = repeatRejectAnalysis_Listener.isApplyChecked();
Assert.assertEquals(true, val);
}
You have to inject the RepeatRejectAnalysis class dependency into your repeatRejectAnalysis_Listener. For example:
Use setter
RepeatRejectAnalysis rs =Mockito.mock(RepeatRejectAnalysis.class);
Mockito.when(rs.getApplytoAllState()).thenReturn(true);
repeatRejectAnalysis_Listener.setAnalysis(rs);
boolean val=repeatRejectAnalysis_Listener.isApplyChecked();
Use #InjectMocks
public class ListenerTest{
#InjectMocks
private Listener repeatRejectAnalysis_Listener = new Listener();
#Mock
private RepeatRejectAnalysis rs;
#Before
public void init(){
MockitoAnnotation.initMocks(this);
}
// reuse the exact same method as you have now.
#Test
public void testIsApplyChecked() {
JCheckBox Rra_Apply_Field=Mockito.mock(JCheckBox.class);
Mockito.when(Rra_Apply_Field.isSelected()).thenReturn(true);
RepeatRejectAnalysis rs =Mockito.mock(RepeatRejectAnalysis.class);
Mockito.when(rs.getApplytoAllState()).thenReturn(true);
boolean val=repeatRejectAnalysis_Listener.isApplyChecked();
Assert.assertEquals(true, val);
}
}
The other answer is correct about that one missing piece of mocking that you need. But then: none of the mocking that you have in your current test case seems to be required.
The idea of tests is to use a (minimal!) setup containing exactly those steps that are really mandatory to enable a test.
There is no point in mocking a JCheckBox ... when the method you intend to test doesnt make use of that check box in any way!

Categories