how to resolve - Parameter specified as non-null is null - java

I have unit test in which I am trying to check is a use case is called with the right parameters but I get an error
java.lang.IllegalArgumentException: Parameter specified as non-null is null: method com.xx.xxx.clean.orderview.domain.OnStandUseCaseCoroutine$Params.<init>, parameter serviceType
#Test
fun `when notifyOnStand is called then we create a TimestampedAction with the correct user id, vehicle, timestamp and pass that to the usecase`() {
val actionCaptor = argumentCaptor<TimestampedAction>()
val timestamp = DateTime.now()
every(noServiceRequiredBus.get()).thenReturn(Observable.just(REQUESTED))
every(timingsUpdater.timestampCalculator(any(), any())).thenReturn(timestamp)
baseOrderViewPresenter.setView(view)
baseOrderViewPresenter.notifyOnStand()
runBlocking {
verify(onStandUseCaseCoroutine).run(OnStandUseCaseCoroutine.Params(any(), any(), capture(actionCaptor)))
}
}
Use case which will get called when when called baseOrderViewPresenter.notifyOnStand() from tets case
class OnStandUseCaseCoroutine #Inject constructor(
private val orderRepository: OrderRepository,
private val serviceOrderTypeProvider: ServiceOrderTypeProvider
) : UseCaseCoroutine<GenericResponse, OnStandUseCaseCoroutine.Params> (){
override suspend fun run(params: Params) =
orderRepository.notifyOnStandSuspend(serviceOrderTypeProvider.apiPathFor(params.serviceType), params.id, params.action)
data class Params(val serviceType: String, val id: String, val action: TimestampedAction)
}
Presenter layer which has the call to use case
private fun onstandUseCaseCoroutines(serviceType: String, id: String, action: TimestampedAction, callback: (GenericResponse?) -> Unit) {
try {
onStandUseCaseCoroutine(OnStandUseCaseCoroutine.Params(serviceType, id, action)) {
callback.invoke(it)
}
} catch (exception: Exception) {
onStandResponseErrors()
}
}
how can I fix this please
I tried changing to bellow code but that did not fix it, I am not sure what to do the capture(actionCaptor) bit if that is the issue
runBlocking {
verify(onStandUseCaseCoroutine).run(OnStandUseCaseCoroutine.Params(anyString(), anyString(), capture(actionCaptor)))
}
Any suggestions please
Thanks
R

Related

how to mock a method call inside another method in same class

I am trying to test a method methodB (as shown in the code below). I want to return directly from methodA without going into the actual code of methodA.
I have used when/thenReturn and doReturn/when but didn't get any success. The test case goes into the real code of methodA. Also tried using spy with Class A instance but didn't get any success.
Actual Class
class A{
fun methodA(String a): String{
// do something
throw new Exception("An error occured");
}
fun methodB(String b): String{
try{
methodA("test")
} catch (e: Exception){
println(e.message());
}
}
}
Test Class
class ATest{
private lateinit var a: A
#Before
fun setUp() {
a= A() // I am initializing services in real scenario
}
#Test
fun `when methodB is not valid then throw Exception`(){
val aMock = mock(A)
Mockito.when(aMock.methodA("test") )
.thenThrow(UserException.INVALID_REQUEST())
// When
val exception: Exception = Assert.assertThrows(
UserException::class.java
) {
a.methodB("test b")
}
val expectedMessage = "INVALID"
val actualMessage = exception.message
// Then
Assert.assertTrue(actualMessage!!.contains(expectedMessage))
}
}
Can anyone please help?
val a = A()
val aSpy = Mockito.spy(a)
Mockito.when(aSpy.methodA(ArgumentMatchers.any())).thenThrow(UserException.INVALID_REQUEST())
you need to get a real instance of class A and then wrap it inside a programmable wrapper which is a spy.
The param matcher of the when statement is the 2nd point of failure since "Test" is not the same instance then the "test b" string. So you dont need to verify some parameter so skip it.
If you want to verify the used parameter you can use a captor instead of ANY().

AspectJ - Get method parameter value by path?

I have an authorizaton Aspect that checks specific conditions based on method annotation.
This specific example shows annotation to mark a method that is only accessible by customer service. But unfortunately this isn't the only condition.
We have to confirm the customerServiceId that is also passed as one of method parameters. The parameter containing customerServiceId is pretty nested, so I was wondering if it's possible to get parameter value by some kind of a "path".
So let's say we have this method:
fun updateRemoteConfig(val remoteConfig: RemoteConfig) { doSomething() }
RemoteConfig class is pretty nested, so the path to customerServiceId would be something like: remoteConfig.customerService.id
What I would like to achieve is mark the method with annotation:
#CustomerServiceAccess(customerServiceIdPath = "remoteConfig.customerService.id")
And the value would then be fetched inside Aspect method. But I have no idea how to get to the specified value by path. Is it even possible?
The unknown is where arrows are in the code. Here's rest of the aspect:
#Aspect
class AuthorizationAspect {
#Pointcut("#annotation(com.my.project.annotations.CustomerServiceAccess)")
fun customerServiceAccess() = Unit
#Before("customerServiceAccess()")
fun checkAccess(joinPoint: JoinPoint) {
val methodSignature = joinPoint.signature as MethodSignature
val method = methodSignature.method
val canAccess = mutableListOf<() -> Boolean>()
.apply {
addAll(method.getAnnotationsByType(CustomerServiceAccess::class.java).map { it.canAccess(method) })
}
.any { it() }
if (!canAccess) {
throw UnauthorizedException(message = "User cannot perform this action")
}
}
private fun CustomerServiceAccess.canAccess(val method: Method): () -> Boolean = {
->> val customerServiceIdParam = method.getParameterByPath(getCustomerServiceIdPath())
SecurityContext.isCustomerService && SecurityContext.customerServiceId == customerServiceIdParam
}
private fun CustomerServiceAccess.getCustomerServiceIdPath(): String = this.customerServiceIdPath
}
#Retention(AnnotationRetention.RUNTIME)
#Target(AnnotationTarget.FUNCTION)
annotation class CustomerServiceAccess(val customerServiceIdPath: String)

rxjava using Single to pass a parameter in the doOnSuccess

Java 8
io.reactivex:rxjava:1.3.6
kotlin 1.2.21
I am trying to pass a parameter in the doOnSuccess using a Single.
However, I am getting an error, that I can't seem to solve.
class TranslateInteractor(val repository: Respository) {
fun requestNetworkTranslated(message: String): Completable {
return repository.fetchTranslation(message)
.doOnSuccess { handleTranslationResponse(message, it) }.toCompletable()
}
private fun handleTranslationResponse(message, String, translatedResponse: TranslatedResponse) {
saveTranslation(
"",
translatedResponse.content,
translatedResponse.translationEngine)
}
private fun saveTranslation(message: String, content: String, engine: String) {
/* Save to local storage */
}
}
The error is in the .doOnSuccess. As I want to pass the message to the handleTranslationResponse.
Type mismatch: inferred type is String but TranslatedResponse was expected
How can I pass the message and what I get from the TranslatedResponse back to the HandleTranslationResponse?
The repository which is a java class that returns a single:
public class Respository {
private NetworkAPI networkAPI;
public Single<TranslatedResponse> fetchTranslation(final String message) {
return networkAPI.fetchTranslation(new TranslateRequest(message));
}
}
My Data classes in Kotlin are:
data class TranslatedResponse(
val content: String,
val translationEngine: String)
And request
data class TranslateRequest(val message: String)
For the networkAPI I have the following in java snippet:
public interface NetworkAPI {
Single<TranslatedResponse> fetchTranslation(TranslateRequest request);
}
Many thanks for any suggestions,
The reason you can't do that is because doOnSucess takes only one parameter, which is whatever the Repository returns.
You'll need to somehow add your original message to the response that the Repository returns. There are a couple of options (e.g. using a Pair or a new data class)
An example:
data class Translation(
val originalMessage: String,
val translatedMessage: TranslationResponse
)
Now your Repository becomes:
public class Respository {
private NetworkAPI networkAPI;
public Single<TranslatedResponse> fetchTranslation(final String message) {
return new Translation(
message,
networkAPI.fetchTranslation(new TranslateRequest(message)
);
}
}
Finally, handleTranslationResponse now takes a Translation instead, which makes your interactor look like:
class TranslateInteractor(val repository: Respository) {
fun requestNetworkTranslated(message: String): Completable {
return repository.fetchTranslation(message)
.doOnSuccess { handleTranslationResponse(it) }.toCompletable()
}
private fun handleTranslationResponse(translation: Translation) {
saveTranslation(
translation.originalMessage,
translation.translatedMessage.content,
translation.translatedMessage.translationEngine)
}
private fun saveTranslation(message: String, content: String, engine: String) {
// do whatever you want!
}
}

Unit test for Kotlin lambda callback

Let's say we have the following function to test
fun loadData(dataId: Long, completion: (JsonElement?, Exception?) -> Unit) {
underlayingApi.post(url = "some/rest/url",
completion = { rawResult, exception ->
val processedResult = processJson(rawResult)
completion(processedResult, exception)
})
}
It's clear to me how to mock, inject, stub and verify the calls to underlayingApi.
How to verify the result returned via completion(processedResult, exception)?
To test the lambdas behavior, the underlayingApi has to be mocked where the lambda is invoked via the InvoactionOnMock object like this.
`when`(underlayingApi.post(eq("some/rest/url"),
any())).thenAnswer {
val argument = it.arguments[1]
val completion = argument as ((rawResult: String?, exception: Exception?) -> Unit)
completion.invoke("result", null)
}
This leads to the invocation of the callback within the object under test. Now to check if the callback out of the object under test is working verify it like that.
objUnderTest.loadData(id,
{ json, exception ->
assert....
})
Building on Martin's answer, here is my approach without lint warnings:
import com.nhaarman.mockito_kotlin.*
#Test
fun loadData() {
val mockUnderlyingApi: UnderlayingApi = mock()
val underTest = ClassBeingTested()
underTest.underlayingApi = mockUnderlyingApi
whenever(mockUnderlyingApi.post(eq("some/rest/url"), any())).thenAnswer {
val completion = it.getArgument<((rawResult: String?, exception: Exception?) -> Unit)>(1)
completion.invoke("result", null)
}
underTest.loadData(0L,
{ jsonElement, exception ->
// Check whatever you need to check
// on jsonElement an/or exception
})
}

Refactor code to not throw Mockito's UnnecessaryStubbingException

I have a simple view with button that starts Intent.ACTION_PICK for result and than displays chosen contact on screen. To do that following steps must be taken:
check if android.permission.READ_CONTACTS is granted
open contact activity
select contact and go back to app
check for android.permission.READ_CONTACTS again
find contact by given uri
show contact on screen
I want to test scenario when one open contacts than revokes permission and goes back to app with selected contact. Expected result is not to call method that find contacts by its uri.
Unfortunately current implementation throws:
org.mockito.exceptions.misusing.UnnecessaryStubbingException:
for:
whenever(interactor.getContact(any())).thenReturn(Maybe.just(Contact()).doOnSuccess { find = true })
I know that I can replace StrictStubs with Silent but I'm looking for better solution with refactoring current code.
All necessary class and test:
class Contact
interface View {
val contactClicks: Observable<Any>
fun setContact(contact: Contact)
}
interface Interactor {
fun getContact(uri: String): Maybe<Contact>
}
interface Router {
fun goToContacts(): Maybe<String>
}
interface Permissioner {
fun requestReadContacts(): Single<Boolean>
}
class Presenter(
private val view: View,
private val interactor: Interactor,
private val router: Router,
private val permissioner: Permissioner
) {
private val disposables: CompositeDisposable = CompositeDisposable()
fun bindView() {
view.contactClicks
.flatMapSingle { permissioner.requestReadContacts() } //ask first time before opening contacts
.filter { it }
.flatMapMaybe { router.goToContacts() }
.flatMapMaybe {
permissioner.requestReadContacts() //ask second time before using ContentResolver
.filter { granted -> granted }
.flatMap { _ -> interactor.getContact(it) }
}
.subscribeBy { view.setContact(it) }
.addTo(disposables)
}
}
#RunWith(MockitoJUnitRunner.StrictStubs::class)
class PresenterTest {
#Mock
lateinit var view: View
#Mock
lateinit var router: Router
#Mock
lateinit var permissioner: Permissioner
#Mock
lateinit var interactor: Interactor
#InjectMocks
lateinit var presenter: Presenter
private val contactClickSubject = PublishSubject.create<Any>()
#Before
fun setUp() {
whenever(view.contactClicks).thenReturn(contactClickSubject)
}
#Test
fun shouldNotFindContactWhenReturnedWithUriAndPermissionNotGrantedSecondTime() {
var firstTimeAsk = true
whenever(permissioner.requestReadContacts()).thenReturn(Single.fromCallable {
if (firstTimeAsk) {
firstTimeAsk = false
return#fromCallable true
} else {
return#fromCallable false
}
})
whenever(router.goToContacts()).thenReturn(Maybe.just("contact"))
var find = false
whenever(interactor.getContact(any())).thenReturn(Maybe.just(Contact()).doOnSuccess { find = true })
presenter.bindView()
contactClickSubject.onNext(Any())
assertFalse(find)
}
}
UnnecessaryStubbingException means you are stubbing something, but not really using it. And that's correct, in your case interactor.getContact should be never called in test - this is desired behaviour. So there is no point in stubbing it.
The simplest solution would be to remove unnecessary variable var find = false and stubbing - substitute them with assertion at the end of your test:
verify(interactor, never()).getContact(any())
This is equivalent to your current solution but more straightforward than using helper variables.

Categories