How to mock Context without the #Mock annotation - android-studio

I'm currently refactoring unit tests and I'm trying to use
import com.nhaarman.mockitokotlin2.mock as much as possible.
I was trying to mock Context like this
private val context = mock<Context>
However, it's throwing this exceptions:
java.lang.RuntimeException: Method getMainLooper in android.os.Looper not mocked.
My suspicion is that Context cannot be mocked this way private val context = mock<Context> and that it cannot be mocked without the #Mock annotation.
Before, Context was mocked like this:
#Mock
lateinit var context: Context
Is my suspicion correct? and if so, could I please get an explanation as to why it can't be mocked that way? Is there a way around this?

You can use MockContext. Official documentation here : https://developer.android.com/reference/android/test/mock/MockContext
private lateinit var mockContext: MockContext
#Before
fun setUp() {
mockContext = MockContext()
}

Related

Parameter specified as non-null is null when using Mokito anyObject() on Kotlin function

My code as below, refering to the solution in https://stackoverflow.com/a/30308199/3286489
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.MockitoAnnotations
import org.mockito.Mockito.*
class SimpleClassTest {
private fun <T> anyObject(): T {
Mockito.anyObject<T>()
return uninitialized()
}
private fun <T> uninitialized(): T = null as T
lateinit var simpleObject: SimpleClass
#Mock lateinit var injectedObject: InjectedClass
#Before
fun setUp() {
MockitoAnnotations.initMocks(this)
}
#Test
fun testSimpleFunction() {
simpleObject = SimpleClass(injectedObject)
verify(injectedObject).settingDependentObject(anyObject())
}
}
I still have the below error
java.lang.IllegalArgumentException: Parameter specified as non-null is null: method my.package.InjectedClass.settingDependentObject, parameter dependentObject
Did I miss anything?
UPDATED
Below is the code tested (simplest form and working)
class SimpleClass(val injectedClass: InjectedClass) {
fun simpleFunction() {
injectedClass.settingDependentObject(DependentClass(Response.Builder().build()))
}
}
open class DependentClass(response: Response) {
}
open class InjectedClass() {
lateinit var dependentObject: DependentClass
fun settingDependentObject(dependentObject: DependentClass) {
this.dependentObject = dependentObject
}
}
By default Kotlin classes and members are final. Mockito cannot mock final classes or methods.
Thus when you write:
verify(injectedObject).settingDependentObject(anyObject())
the real implementation is called which requires non null argument.
To fix that either open your class and method or, even better, change SimpleClass to accept an interface as its constructor argument and mock the interface instead.
There is a project specifically to help deal with Kotlin "closed by default" in unit testing with Mockito. For JUNIT, you can use the kotlin-testrunner which is an easy way to make any Kotlin test automatically open up classes for testing as they are loaded by the classloader. Usage is simple, just add one annotation of #RunWith(KotlinTestRunner::class), for example:
#RunWith(KotlinTestRunner::class)
class MyKotlinTestclass {
#Test
fun test() {
...
}
}
This is thoroughly covered in the article Never say final: mocking Kotlin classes in unit tests
This covers your use case in an automatic way by allowing all classes to be mocked that otherwise would not be allowed.
I ran into the same issue with Mockito when using RETURNS_DEEP_STUBS. It seems like nulls are still returned for nested objects, even when using the kotlin-allopen plugin.
Please check out and comment on this issue on Mockito if you're having the same problem.
You can use this function instead
inline fun <reified T : Any> any(): T = Mockito.any(T::class.java) ?: T::class.java.newInstance()

Kotlin lazy block not executed when using Mockito and InjectMocks [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 6 years ago.
Improve this question
I'm using Mockito to test my Kotlin code. It's a web app and I use spring to inject values into some fields.
For example, my class snippet looks something like this:
class MyComponent {
#Inject private lateinit var request: HttpServletRequest
#Inject private lateinit var database: Database
To mimic this in my unit test I use the #Mock and #InjectMocks annotations from Mockito. So my test looks something like this:
class MyComponentTest {
#Mock private lateinit var request: HttpServletRequest
#Mock private lateinit var database: Database
#InjectMocks private lateinit var sut: MyComponent
#Before
fun setup() {
MockitoAnnotations.initMocks(this)
}
Which all works fine. However, I also have a lazy initialization block in my component like this:
val user: User by lazy {
database.findUser()
}
fun getUsername(): String {
return user.name
}
When my test calls myComponent.getUsername() I would expect database.findUser() to be called as it initializes user but this doesn't happen.
If I put a breakpoint in the lazy block, it's never hit. Now I am assuming this is something to do with the way Mockito and #InjectMocks must 'touch' user but I don't really know. If I construct MyComponent manually then the lazy block is executed - but this won't inject my mocks.
How can I ensure the lazy block is called correctly from my test?
UPDATE: After a week absence, attempting to reproduce this without any changes and I could not. Can't explain it.
I've tried to reproduce your problem and was not able to do so. This gist provides a working example.
However I would recommend revisiting the way you write tests. Consider following example:
class MyComponentTest {
val request = mock<HttpServletRequest>()
val database = mock<Database>()
val sut = MyComponent(request, database)
#Test
fun username() {
Mockito.`when`(database.findUser()).thenReturn(User("test"))
val username = sut.getUsername()
MatcherAssert.assertThat(username, Matchers.equalTo("test"))
}
}
Which in my opinion is easier to understand than the one in mentioned the gist.
In case you're interested the mock helper function is a one liner:
inline fun <reified T : Any> mock() = Mockito.mock(T::class.java)
A full updated example can be found in this gist.

Mockito implemetation for formhandlers in ATG

I am new to Mockito as a concept. Can you please help me understand using Mockito for formhandlers in ATG. Some examples will be appreciated.
There is a good answer (related to ATG) for other similar question: using-mockito-for-writing-atg-test-case. Please review if it includes what you need.
Many of ATG-specific components (and form handlers particularly) are known to be "less testable" (in comparison to components developed using TDD/BDD approach), b/c design of OOTB components (including reference application) doesn't always adhere to the principle of having "Low Coupling and High Cohesion"
But still the generic approach is applicable for writing unit-tests for all ATG components.
Below is a framework we've used for testing ATG FormHandlers with Mockito. Obviously you'll need to put in all the proper bits of the test but this should get you started.
public class AcmeFormHandlerTest {
#Spy #InjectMocks private AcmeFormHandler testObj;
#Mock private Validator<AcmeInterface> acmeValidatorMock;
#Mock private DynamoHttpServletRequest requestMock;
#Mock private DynamoHttpServletResponse responseMock;
private static final String ERROR1_KEY = "error1";
private static final String ERROR1_VALUE = "error1value";
#BeforeMethod(groups = { "unit" })
public void setUp() throws Exception {
testObj = new AcmeFormHandler();
initMocks(this);
}
//Test the happy path scenario
#Test(groups = { "unit" })
public void testWithValidData() throws Exception {
testObj.handleUpdate(requestMock, responseMock);
//Assume your formhandler calls a helper method, then ensure the helper method is called once. You verify the working of your helper method as you would do any Unit test
Mockito.verify(testObj).update(Matchers.refEq(requestMock), Matchers.refEq(responseMock), Mockito.anyString(), (AcmeBean) Mockito.anyObject());
}
//Test a validation exception
#Test(groups = { "unit" })
public void testWithInvalidData() throws Exception {
Map<String, String> validationMessages = new HashMap<String, String>();
validationMessages.put(ERROR1_KEY, ERROR1_VALUE);
when(acmeValidatorMock.validate((AcmeInterface) Mockito.any())).thenReturn(validationMessages);
testObj.handleUpdate(requestMock, responseMock);
assertEquals(1, testObj.getFormExceptions().size());
DropletFormException exception = (DropletFormException) testObj.getFormExceptions().get(0);
Assert.assertEquals(exception.getMessage(), ERROR1_VALUE);
}
//Test a runtime exception
#Test(groups = { "unit" })
public void testWithRunProcessException() throws Exception {
doThrow(new RunProcessException("")).when(testObj).update(Matchers.refEq(requestMock), Matchers.refEq(responseMock), Mockito.anyString(), (AcmeBean) Mockito.anyObject());
testObj.handleAddGiftCardToCart(requestMock, responseMock);
assertEquals(1, testObj.getFormExceptions().size());
DropletFormException exception = (DropletFormException) testObj.getFormExceptions().get(0);
Assert.assertEquals(exception.getMessage(), GENERAL_ERROR_KEY);
}
}
Obviously the above is just a framework that fit in nicely with the way in which we developed our FormHandlers. You can also add validation for redirects and stuff like that if you choose:
Mockito.verify(responseMock, Mockito.times(1)).sendLocalRedirect(SUCCESS_URL, requestMock);
Ultimately the caveats of testing other people's code still applies.
Here's what I do when I unit test a form handler (at least until I manage to release a major update for AtgDust). Note that I don't use wildcard imports, so I'm not sure if this causes any namespace conflicts.
import static org.mockito.Mockito.*;
import static org.mockito.MockitoAnnotations.initMocks;
import org.junit.*;
import static org.junit.Assert.assertThat;
import static org.hamcrest.CoreMatchers.*;
import atg.servlet.*;
import some.form.handler.FormHandler;
#RunWith(JUnit4.class)
public class FormHandlerTest {
#Mock DynamoHttpServletRequest request;
#Mock DynamoHttpServletResponse response;
FormHandler handler;
#Before
public void setup() {
initMocks(this);
handler = new FormHandler();
}
#Test
public void testSubmitHandlerRedirects() {
handler.handleSubmit(request, response);
verify(response).sendLocalRedirect(eq("/success.jsp"), eq(request));
assertThat(handler.getFormError(), is(false));
}
}
The basic idea is to set up custom behavior for mocks/stubs using when() on the mock object method invocation to return some test value or throw an exception, then verify() mock objects were invoked an exact number of times (in the default case, once), and do any assertions on data that's been changed in the form handler. Essentially, you'll want to use when() to emulate any sort of method calls that need to return other mock objects. When do you need to do this? The easiest way to tell is when you get NPEs or other runtime exceptions due to working with nulls, zeros, empty strings, etc.
In an integration test, ideally, you'd be able to use a sort of in-between mock/test servlet that pretends to work like a full application server that performs minimal request/session/global scope management. This is a good use for Arquillian as far as I know, but I haven't gotten around to trying that out yet.

Mocking two objects of the same type with Mockito

I'm writing unit tests using Mockito and I'm having problems mocking the injected classes. The problem is that two of the injected classes are the same type, and only differentiated by their #Qualifier annotation. If I tried to simply mock SomeClass.class, that mock is not injected and that object is null in my tests. How can I mock these objects?
public class ProfileDAL {
#Inject
#Qualifier("qualifierA")
private SomeClass someClassA ;
#Inject
#Qualifier("qualifierB")
private SomeClass someClassB ;
//...various code, not important
}
#RunWith(MockitoJUnitRunner.class)
public class ProfileDALLOMImplTest {
#InjectMocks
private ProfileDALLOMImpl profileDALLOMImpl = new ProfileDALLOMImpl();
#Mock
private SomeClass someClassA;
#Mock
private SomeClass someClassB;
private SomeResult mockSomeResult = mock(SomeResult.class);
#Test
public void testSomeMethod() {
when(someClassA .getSomething(any(SomeArgment.class)).thenReturn(mockSomeResult);
Int result = profileDALLOMImpl.someTest(This isn't relevant);
}
}
I have tried mocking two objects with the same type with Mockito 1.9.5 using JUnit and it works.
See: http://static.javadoc.io/org.mockito/mockito-core/1.9.5/org/mockito/InjectMocks.html
Relevant type info from the doc:
"Field injection; mocks will first be resolved by type, then, if there is several property of the same type, by the match of the field name and the mock name."
And this one which seems to say you should make the mock name match the field name for all your mocks when you have two of the same type:
"Note 1: If you have fields with the same type (or same erasure), it's better to name all #Mock annotated fields with the matching fields, otherwise Mockito might get confused and injection won't happen."
Perhaps this latter one is biting you?
Just confirmed what Splonk pointed out and it works that way in Mockito 1.9.5, as soon as I removed one of the mocked classes, it failed.
So, in your case, make sure you have both of the mocked classes with the same name as in the class in your test:
#Mock
private SomeClass someClassA;
#Mock
private SomeClass someClassB;
If you don't use annotation, you get something like
public class MyClass {
private MyDependency myDependency;
public void setMyDependency(MyDependency myDependency){
this.myDependency = myDependency;
}
}
and
import org.junit.Before;
import org.junit.Test;
import static org.mockito.Mockito.*;
public class MyTest {
private MyClass myClass;
private MyDependency myDependency;
#Before
public void setUp(){
myClass = new MyClass();
myDependency = mock(MyDependency.class);
myClass.setMyDependency(myDependency);
}
#Test
public void test(){
// Given
// When
// Then
}
}
You can do just the same if your object has its dependencies specified via constructor rather than via setter. I guess your dependency injection framework can annotate the setters the same way you annotate private fields, but now your tests don't rely on any dependency injection framework.

JUnit #Before method ordering in Groovy

I am used to JUnit running #Before methods in a superclass before #Before methods in a subclass. However, I've got a Groovy test class which inherits from another Groovy class, and they both contain #Before methods; the problem I have is that #Before method in the test class is running before the one in its superclass, and I'm getting NPEs from uninitialised variables (the superclass is supposed to take care of that).
The superclass is something like this:
import groovyx.net.http.RESTClient
import org.junit.Before
abstract class BaseTestClass {
def client
#Before
void setUp() {
client = new RESTClient()
}
}
And the subclass is something like this:
import org.junit.Before
class TestClass extends BaseTestClass {
#Before
void setUp() {
client.post(path: '/entity', body: '{"id":"test"}')
}
...
}
This is a simplified version, but I get the error: java.lang.NullPointerException: Cannot invoke method post() on null object in the setUp() method of the subclass. Any ideas what could cause this behaviour? All the docs say it should be the other way round, and I've never previously experienced any different.
I'm running using the maven-failsafe-plugin, junit-4.10 and jdk-1.6.0_31. Interestingly, I have other Groovy test classes in the same place (same package, same project, same directory) which do not suffer from this problem - the ordering of #Before methods is correct; furthermore, it appears to be deterministic - it's always the same test class that has the problem.
Thanks!
You named both of your #Before methods setUp(). The child's setUp() method overrides the parent's one. So the line client = new RESTClient() is never called.
Just pick another name.

Resources