JUnit test not sending values as parameters to function (Kotlin) - android

I am creating a simple junit test to test a function in my view model but the first assertion fails as the function I call returns null. When I debug the function I call has null parameters which is weird cause I pass them in.
I have spent time debugging and searching for why I am having that issue but I have found nothing that fixes my issue or tells me what the issue is.
#RunWith(MockitoJUnitRunner::class)
class CurrencyUnitTest {
#Rule
#JvmField
val rule = InstantTaskExecutorRule()
#Mock
val currencyViewModel : CurrencyViewModel = mock(CurrencyViewModel::class.java)
#Before
fun setUp() {
MockitoAnnotations.initMocks(this)
val rates: HashMap<String, Double> =
hashMapOf(
"USD" to 1.323234,
"GBP" to 2.392394,
"AUD" to 0.328429,
"KWR" to 893.4833
)
val currencyRates = MutableLiveData<Resource<CurrencyRatesData?>>()
val resource = Resource<CurrencyRatesData?>(Status.SUCCESS, CurrencyRatesData("CAD", rates, 0))
currencyRates.value = resource
`when`(currencyViewModel.currencyRatesData).thenReturn(currencyRates)
val baseCurrency = MutableLiveData<String>()
baseCurrency.value = "CAD"
`when`(currencyViewModel.baseCurrency).thenReturn(baseCurrency)
}
#Test
fun calculateValueTest() {
// this fails
assertEquals("0.36", currencyViewModel.calculateValue("AUD", "1.11"))
}
}

Mocked classes will not really be called. If you want to test your currencyViewModel.calculateValue() method, create a real object of that class and mock possible constructor arguments.

To add to what Ben has said: the class you want to test has to be a real object, not a mock. A mock "does nothing" per default, and only does what you do it to tell you, so to test it does not make any sense.
What you mock is the dependencies of the class you test, i.e. the objects you pass to its' constructor.
In short: if you want to test CurrencyViewModel, create an object of it instead of mocking it.

Related

Android MVVM testing with Mockito, mock repository.observeValue() has problem

I'm trying to test MVVM with Mockito.
The architecture of MVVM is similar to Android architecture blueprints.
We observe data from repository as LiveData.
And try to test observed value like below code.
class SplashViewModel(
private val appRepository: AppRepository
) {
val appInfo: LiveData<AppInfo> = appRepository.observeAppInfo()
}
#Test
fun getAppInfo() {
`when`(appRepository.observeAppInfo())
.thenReturn(appInfoData)
assertEquals(appInfoData, viewModel.appInfo.getOrAwaitValue())
}
The crucial point is viewModel.appInfo returns null, despite of I used mockito.
The problem
The creation of ViewModel is faster than using mockito.
So appInfo property is initialized with null, cause it dosen't know what observeAppInfo() is.
First solution
At first, I just trying to solve this problem with custom getter. Like this.
class SplashViewModel(
private val appRepository: AppRepository
) {
val appInfo: LiveData<AppInfo> get() = appRepository.observeAppInfo()
}
Now every time I access to appInfo they just re evaluate the data.
But is has it's own problem.
In this situation appVersion is getting error.
val appVersion: LiveData<String> = appInfo.map {
...
}
So every transformation LiveData(Like Transformations, MediatorLiveData) must use custom getter too.
And I felt it's not a great solution.
How do you think of it?
You could use #BeforeClass to make sure your initialisation is run before the tests.
#BeforeClass
fun setup(){
appInfo = appRepository.observeAppInfo()
}
See more

how to create unit test cases for kotlin data classes

I have created few data classes for my sample application. I need to write unit test cases for those data classes now. I am using Junit4.12. Here is my data class:
data class Tracking(val param1 : String?=null, val param2 : String?=null, val param3 : String?=null){}
I tried writing one basic unit test case for this model like below:
#Test
fun tracking()
{
val trackingData= Tracking("7030054",
"skdfksbfbkjsdf",
"dfkhsbfsjf")
Assert.assertEquals("true",trackingData.param1,"7030054")
}
But i don't see it is right way of performing a unit test case. My Objective for unit test case is to assert an exception if user sends null value as an input. Please help me out.
Your values are all String?, so nullable. If you want them to always be non-null, use String instead. Then you don't need a unit-test since non-nullability will be checked by the compiler.
If they can sometimes be null but not always, you have to first write a function that checks that condition.
A very simple example would be something like
fun simpleValidation() {
if(param1 == null) {
throw RuntimeException("Should not be null")
}
}
in the class tracking.
You can than unit test this by
#Test
fun tracking()
{
val trackingData= Tracking(null,
"skdfksbfbkjsdf",
"dfkhsbfsjf")
Assertions.assertThrows(RuntimeException::class.java) { trackingData.simpleValidation() }
}
assuming you are using JUnit5

Mockito testing in MVP kotlin - However, there was exactly 1 interaction with this mock exception

I have developed an application with Kotlin and MVP architecture.I want to do unit testing using Mockito but unable to achieve it.I'm getting "However, there was exactly 1 interaction with this mock exception".
In my application i have used 5 different classes.
View - Interface
Intractor - Interface
IntractorImpl - Class
Presenter - Interfacce
PresenterImpl - Class
View:- It contain all methods required for to communicate activity/fragment.
Intractor:- It contain the result interface methods.
IntractorImpl :- It contain database/server logic, it will implemented from Intractor
Presenter :- It contain methods to access the IntractorImpl class
PresenterImpl :- It is implemented from Presenter and Intractor result methods
This architecture which i followed for implementing, now to implement the Mockito i'm getting confusion and as per the articles i found in google if i try to implement i'm getting "However, there was exactly 1 interaction with this mock exception"
For mockito i have used following imports
//Mockito
testImplementation "org.mockito:mockito-core:2.24.5"
testImplementation "org.mockito:mockito-inline:2.24.5"
Please if anyone knows anything,help me out. First time i'm using Mokito.
If anyone need more information i can post it. Following is my code
class EventTest {
#Mock
val homeActivity = HomeActivity()
lateinit var eventView: HomeView
lateinit var eventInteractorImpl: HomeInteractorImpl
lateinit var eventPresenter: HomePresenter
lateinit var eventInteractor: HomeInteractor.OnEventsReceivedListener
#Before
fun setUpEventPresenter() {
eventView = mock(HomeView::class.java)
eventInteractorImpl = mock(HomeInteractorImpl::class.java)
eventPresenter = HomePresenterImpl(eventView, eventInteractorImpl)
eventInteractor = mock(HomeInteractor.OnEventsReceivedListener::class.java)
}
#Test
fun startEventTest() {
val testEvents = Event(
"1",
"Test",
"Next week we have the vacation planing in Vizag",
"This is for test",
"1",
"01-10-2019",
"26-09-2019",
"8.00",
"10.47",
"",
true
)
val events: ArrayList<Event> = ArrayList<Event>()
events.add(testEvents)
eventPresenter.getEventsList(homeActivity)
verify(eventView).showProgress()
verify(eventView).showEvents(events)
verify(eventView).hideProgress()
}
}
If i put verify(eventView).showProgress() no exception is coming.
override fun getEventsList(context: Context) {
homeView.showProgress()
homeInteractor.getEvents(context, this)
}
In getEvents() method we are calling server/local database, for Server we are using Retrofit.
According to your code and explanation you gave in comments, the error message you're getting is correct because you're invoking mock interactor which cannot invoke other view functions.
Therefore, only thing you should verify in startEventTest() is verify(eventView).showProgress() and verify(eventInteractorImpl).getEvents(any(), any()):
#Test
fun startEventTest() {
val testEvents = Event(
"1",
"Test",
"Next week we have the vacation planing in Vizag",
"This is for test",
"1",
"01-10-2019",
"26-09-2019",
"8.00",
"10.47",
"",
true
)
val events: ArrayList<Event> = ArrayList<Event>()
events.add(testEvents)
eventPresenter.getEventsList(homeActivity)
verify(eventView).showProgress()
verify(eventInteractorImpl).getEvents(any(), any())
}
If you still want to test verify(eventView).showEvents(events) and verify(eventView).hideProgress(), instead of mocking interactor, you should create instance of it.

How to unit test retrofit call?

For Example I have a retrofit interface such as:
interface SampleService {
fun getSomething(#body someBody: SomeBody)
}
Now I have a class which uses this interface such as:
class UserRequester(val service: SampleService) {
fun doGetSomething(someValue: String) {
val response = service.getSomething(SomeBody(someValue))
// ...
}
}
I want to test this class but dont know how to mock it.
I'm trying the following:
val mockSampleService = mock()
val userRequester = UserRequester(mockSampleService)
val requestBody = SomeBody(someString))
when(mockSampleService.getSomething(requestBody)).return(myExpectedValue)
....
My problem is that since I create the request object inside the function, I could not make the mock when().thenReturn() to work since i am technically passing two different object.
How should I test this? Thanks in advance.
The mocking problem (UserRequester)
You are not able to mock the mockSampleService method because your class is creating the SomeBody object and is different from the SomeBody object you are creating in your test.
Now you have 2 options:
Use Mockito.any() in your test, in this way you basically say that whatever your method is gonna use as parameter you will return the mocked behaviour
Use a factory that given a someString returns you a SomeObject like this:
// the factory
class SomeObjectFactory{
fun createSomeObject(someString: String): SomeObject {
return SomeObject(someString)
}
}
//the class
class UserRequester(
val service: SampleService, val factory: SomeObjectFactory
) {
fun doGetSomething(someValue: String) {
val response = service.getSomething(factory.createSomeObject(someValue))
// ...
}
}
//the test
class MyTest{
#Test
fun myTestMethod(){
val mockSampleService = mock()
val factory = mock()
val someBody = mock()
val userRequester = UserRequester(mockSampleService, factory)
`when`(factory.createSomeObject(someString)).thenReturn(someBody)
`when`(mockSampleService.getSomething(someBody)).thenReturn(myExpectedValue)
//rest of the code
}
}
The second approach is the cleanest one.
Testing Retrofit calls (SampleService)
I wouldn't unit test a Retrofit call.
When you are dealing with frameworks, apis, databases, shared preferences is always preferable to do integration tests instead of unit tests.
In this way you are actually testing that your code is working with the outside world.
I suggest you to test Retrofit calls with MockWebServer (it's a library from Square, the same company that developed OkHttp and Retrofit).
This read may be also helpful.
Probably SomeBody is a plain value object, since Retrofit requests work with value objects. If you define the equals method for the SomeBody class then the eq matcher will work, and you can write using mockito-kotlin:
whenever(mockService.getSomething(eq(SomeBody(someString)))).thenReturn(stubbedResult)
Actually, you can omit the eq matcher, Mockito will use the equals method for matching.
If SomeBody is a Kotlin data class then the equals method is automatically defined by comparing the fields.
If for some reason you don't want to rely on equals, then you can use the argThat matcher defined in mockito-kotlin:
whenever(mockService.getSomething(argThat { theField == someValue })).thenReturn(stubbedResult)
The problem is that there is static dependency on SomeBody's constructor:
val response = service.getSomething(SomeBody(someValue))
What you could do to have control over the instantiation of SomeBody is to use a "provider" or "factory" object, you can inject it in the constructor and invoke it at the right time:
interface SampleService {
fun getSomething(someBody: SomeBody)
}
open class SomeBody(val body: String)
open class UserRequester(
val service: SampleService,
val someBodyProvider: (String) -> SomeBody
) {
fun doGetSomething(someValue: String) {
val response = service.getSomething(someBodyProvider(someValue))
}
}
And mock it in your tests:
val someValue = "foo"
val sampleService: SampleService = mock()
val someBody: SomeBody = mock()
val someBodyProvider: (String) -> SomeBody = mock {
on { invoke(someValue) }.thenReturn(someBody)
}
val userRequester = UserRequester(sampleService, someBodyProvider)
userRequester.doGetSomething("foo")
verify(sampleService).getSomething(someBody)
verify(someBodyProvider).invoke(someValue)
I used an anonymous function but you might as well make it an interface.

Android - mocking issue

I have a custom class:
class MyClass {
var name = ""
fun changeName(newName: String) {
name = newName
}
}
and my testing class:
#Test
fun testVerifyMock() {
val instance: MyClass = mock()
instance.changeName("newname")
Assert.assertEquals("newname", instance.name)
}
I'm faily new to Unit Tests and I'm kinda stuck, can someone please point me to why I get this error:
java.lang.AssertionError:
Expected :newname
Actual :null
Basically the call instance.changeName("newname") doesn't seem to be changing the name since it's always null
Mockito mocks just ignore what you pass to their methods unless you explicitly tell them what to do. In the case of changeName, the parameter is just ignored and therefore the name will remain null. I don't see why you would use a mock here anyway, so just change to:
val instance = MyClass()
...
Here's a post on "when to use mock".

Categories

Resources