Test case is calling actual method even after mocking the method call in ktor framework (kotlin) - kotlin

I am testing an API written in Kotlin using the KTOR framework. For the testing, I am using JUnit5 and Mockito. There is a route class where a route is defined which I need to test. Here is the route class :-
fun Application.configureRouting() {
routing {
post("/someRoute") {
val service = MyService()
val request: JsonNode = call.receive()
launch {
service.dummyFunction(request)
}
val mapper = ObjectMapper()
val responseStr = "{\"status\":\"success\",\"message\":\"Request has been received successfully\"}"
val response: JsonNode = mapper.readTree(responseStr)
call.fireHttpResponse(HttpStatusCode.OK, response)
}
}
}
This is the test case I am writing for it :-
class RouteTest {
#Mock
var service = MyService()
// read the configuration properties
private val testEnv = createTestEnvironment {
config = HoconApplicationConfig(ConfigFactory.load("application.conf"))
}
#Before
fun setUp() = withApplication(testEnv) {
MockitoAnnotations.openMocks(MyService::class)
}
#Test
fun test() = withApplication(testEnv) {
withTestApplication(Application::configureRouting) {
runBlocking {
Mockito.`when`(service.dummyFunction(Mockito.any()).thenReturn(true)
with(handleRequest(HttpMethod.Post, "/someRoute") {
setBody("some body")
}) {
assertEquals(HttpStatusCode.OK, response.status())
}
}
}
}
}
When I run the test, it calls the actual "dummyFunction()" method instead of the mocked one and hence, it is failing. Am I doing something wrong?

Because your service in test is different from the service you mocked. To solve this, you need to inject the service into your class, or pass the service as an argument.
Read more: IoC, DI.

The simplest way to solve your problem is to define the service parameter for the configureRouting method and pass a corresponding argument in the test and production code when calling it.
fun Application.configureRouting(service: MyService) {
routing {
post("/someRoute") {
val request: JsonNode = call.receive()
launch {
service.dummyFunction(request)
}
val mapper = ObjectMapper()
val responseStr = "{\"status\":\"success\",\"message\":\"Request has been received successfully\"}"
val response: JsonNode = mapper.readTree(responseStr)
call.fireHttpResponse(HttpStatusCode.OK, response)
}
}
}
class RouteTest {
#Mock
var service = MyService()
private val testEnv = createTestEnvironment {
config = HoconApplicationConfig(ConfigFactory.load("application.conf"))
}
#Test
fun test() = withApplication(testEnv) {
withTestApplication({ configureRouting(service) }) {
runBlocking {
// Your test...
}
}

Related

mocking a class that depends on firebase in a non-uI test for remote config

I have this class that exposes remote configs to others. I thought by creating a class, I would just mock it when testing others that use it but so far, firebase is blocking me. Not sure what I am doing wrong exactly.
class AppRemoteConfig #Inject constructor() {
private var remoteConfig: FirebaseRemoteConfig = Firebase.remoteConfig
private fun setListeningInterval(): Long {
if (BuildConfig.DEBUG){
return 0;
}
return 86400;
}
init {
val configSettings = remoteConfigSettings {
minimumFetchIntervalInSeconds = setListeningInterval()
}
remoteConfig.setConfigSettingsAsync(configSettings)
remoteConfig.setDefaultsAsync(R.xml.remote_config_defaults)
remoteConfig.fetchAndActivate()
.addOnCompleteListener(OnCompleteListener{
if (it.isSuccessful) {
remoteConfig.activate()
}
})
}
fun getString(key: String): String {
return this.remoteConfig.getString(key)
}
}
Now a class uses it this way:
class GetRData #Inject constructor(
private val _remoteConfig: AppRemoteConfig
) {
operator fun invoke(key): String {
try {
return _remoteConfig.getString(key)
} catch(ex: Exception){
return ""
}
return ""
}
}
Now I want to test GetRData class but I get the error: Default FirebaseApp is not initialized in this process null. Make sure to call FirebaseApp.initializeApp(Context) first.
here is what I have tried:
class GetRDataTest {
private var appRemoteConfig = mockk<AppRemoteConfig>(relaxed = true)
private lateinit var getRData : GetRData
#Before
fun setUp(){
getRData = GetRData(appRemoteConfig)
}
#Test
fun `Should get string value`() {
every { appRemoteConfig.getString("status") } returns "red"
val result = getRData.invoke("status")
verify { appRemoteConfig.getString("status") }
Truth.assertThat(result).isEqualTo("red")
}
}

Testing Soap Consumer. 'uri' must not be empty

I have a method for calling the "marshalSendAndReceive" method on sending a message over Soap.
class SoapConnector : WebServiceGatewaySupport() {
fun getClient(documentId: String): Person {
val request = getSearchRequest(documentId)
val response = webServiceTemplate.marshalSendAndReceive(request) as SearchResponse
return getPerson(response)
}
I also have a configuration file.
#Configuration
class SearchClientConfig {
#Bean
fun marshaller(): Jaxb2Marshaller? {
return Jaxb2Marshaller().apply {
contextPath = "wsdl" //here path to generated java classes from wsdl
}
}
#Bean
fun searchCilent(marshallerJaxb: Jaxb2Marshaller): SoapConnector {
return SoapConnector().apply {
defaultUri = "http://20.40.59.1:8080/cdi/soap/services/ServiceWS"
marshaller = marshallerJaxb
unmarshaller = marshallerJaxb
}
}
}
I want to Mock this method.
#RunWith(SpringRunner::class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#Sql(scripts = ["classpath:db/init.sql"])
#AutoConfigureEmbeddedDatabase(
beanName = "dataSource",
provider = AutoConfigureEmbeddedDatabase.DatabaseProvider.DOCKER
)
class SoapTest : WebServiceGatewaySupport(){
private lateinit var webServiceGatewaySupport: WebServiceGatewaySupport
private lateinit var connector: SoapConnector
#BeforeEach
fun setUp() {
webServiceGatewaySupport = Mockito.mock(WebServiceGatewaySupport::class.java)
}
#Test
fun getClientTest() {
Mockito.`when`(webServiceTemplate.marshalSendAndReceive(ArgumentMatchers.anyObject())).thenReturn(SearchResponse())
connector.getClient(RandomStringUtils.randomAlphabetic(7))
}
}
But there is a bug:
java.lang.IllegalArgumentException: 'uri' must not be empty
I don't understand what the problem is and I don't know how to make a working Mock of this method.

RxJava + Retrofit Unit Test Kotlin Always Failed

I tried to create Unit Test using Rxjava + Retrofit but it always give an error.
I have tried all tutorials and reference related of my questions. I did success when create an unit test of other method (other case), but failed in this case (Rx + retrofit).
Request Data Code:
fun getDetailEvent(idEvent: String?) {
view.showLoading()
apiService.getDetailEvent(idEvent)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnSubscribe {
val compositeDisposable: CompositeDisposable? = null
compositeDisposable?.add(it)
}
.doFinally { view.hideLoading() }
.subscribe({
val listModel = it
if (listModel != null) {
view.onDetailEventLoaded(listModel)
} else {
view.onDetailEventLoadFailed("Empty or Error List")
}
},
{
val errorMessage = it.message
if (errorMessage != null) {
view.onDetailEventLoadFailed(errorMessage)
}
})
}
Unit Test Code :
class DetailNextMatchPresenterTest {
#Mock
private lateinit var view : DetailNextMatchView
#Mock
private lateinit var apiService: ApiService
private lateinit var presenter: DetailNextMatchPresenter
#Before
fun setup(){
MockitoAnnotations.initMocks(this)
presenter = DetailNextMatchPresenter(view, apiService)
}
#Test
fun getDetailEvent() {
val event : MutableList<EventModel> = mutableListOf()
val response = ResponseEventModel(event)
val idEvent = "44163"
`when`(apiService.getDetailEvent(idEvent)
.test()
.assertSubscribed()
.assertValue(response)
.assertComplete()
.assertNoErrors()
)
presenter.getDetailEvent(idEvent)
verify(view).showLoading()
verify(view).onDetailEventLoaded(response)
verify(view).hideLoading()
}
}
I appreciate all suggestion. Thanks
I believe that the issue is that you haven't forced your code to behave synchronously in the context of your test, so the Observable runs in parallel to your test. Try adding this in your setup method:
RxJavaPlugins.setIoSchedulerHandler { Schedulers.trampoline() } If you're using RxJava2. Try looking for a similar method if you're using RxJava 1.

Hoverfly Ktor client Apache Kotlin

I tried to do unit test with Hoverfly to mock external API.
companion object {
#ClassRule #JvmField
val hoverflyRule: HoverflyRule = HoverflyRule.inSimulationMode(dsl(
service("people.zoho.com")
.get("/people/api/forms/P_EmployeeView/records").queryParam("authtoken","TOKEN")
.willReturn(success("{test:test}", "application/json"))
))
}
When I use the Apache client with ktor, that doesn't work. But with another client like khttp, it works. Any ideas why?
You should setup default system proxy in Apache config:
http://hoverfly.readthedocs.io/projects/hoverfly-java/en/latest/pages/misc/misc.html
example with ktor(0.9.3-alpha-3):
class ApplicationMockupTest {
companion object {
#ClassRule
#JvmField
val hoverflyRule: HoverflyRule = HoverflyRule.inSimulationMode(
dsl(
service("people.zoho.com:443")
.get("/people/api/forms/P_EmployeeView/records")
.queryParam("authtoken", "TOKEN")
.willReturn(success("{j:gr}", "application/json"))
)
)
}
#Test
fun exampleTest() = runBlocking<Unit> {
val client = HttpClient(Apache.setupDefaultProxy())
val token = "TOKEN"
val url = "https://people.zoho.com/people/api/forms/P_EmployeeView/records?authtoken=$token"
val requestString = client.get<String>(url)
hoverflyRule.verifyAll()
Unit
}
fun HttpClientEngineFactory<ApacheEngineConfig>.setupDefaultProxy() = config {
customizeClient {
useSystemProperties()
}
}
}

How to verify/test WebClient usage

I need to unit test a class that uses the WebClient. Is there any good way to deal with the WebClient?
With the RestTemplate I could easily use Mockito. Mocking the WebClient is a bit tedious, since deep stubs don't work with the webclient...
I want to test if my code provides the correct headers...
shortened sample code:
public class MyOperations {
private final WebClient webClient;
public MyOperations(WebClient webClient) {
this.webClient = webClient;
}
public Mono<ResponseEntity<String>> get( URI uri) {
return webClient.get()
.uri(uri)
.headers(computeHeaders())
.accept(MediaType.APPLICATION_JSON)
.retrieve().toEntity(String.class);
}
private HttpHeaders computeHeaders() {
...
}
}
This is aimed to unit, not integration tests...
Implemented in Kotlin, this is a bit rudimentary, but it's effective. The idea can be extracted from this pieces of code below
First, a WebClient kotlin extension
import org.mockito.ArgumentMatchers.anyString
import org.mockito.Mockito.*
import org.springframework.web.reactive.function.client.WebClient
import org.springframework.web.reactive.function.client.WebClientResponseException
import reactor.core.publisher.toMono
fun WebClient.mockAndReturn(data: Any) {
val uriSpec = mock(WebClient.RequestBodyUriSpec::class.java)
doReturn(uriSpec).`when`(this).get()
doReturn(uriSpec).`when`(this).post()
...
val headerSpec = mock(WebClient.RequestBodyUriSpec::class.java)
doReturn(headerSpec).`when`(uriSpec).uri(anyString())
doReturn(headerSpec).`when`(uriSpec).uri(anyString(), anyString())
doReturn(headerSpec).`when`(uriSpec).uri(anyString(), any())
doReturn(headerSpec).`when`(headerSpec).accept(any())
doReturn(headerSpec).`when`(headerSpec).header(any(), any())
doReturn(headerSpec).`when`(headerSpec).contentType(any())
doReturn(headerSpec).`when`(headerSpec).body(any())
val clientResponse = mock(WebClient.ResponseSpec::class.java)
doReturn(clientResponse).`when`(headerSpec).retrieve()
doReturn(data.toMono()).`when`(clientResponse).bodyToMono(data.javaClass)
}
fun WebClient.mockAndThrow() {
doThrow(WebClientResponseException::class.java).`when`(this).get()
doThrow(WebClientResponseException::class.java).`when`(this).post()
...
}
Then, the unit test
class MyRepositoryTest {
lateinit var client: WebClient
lateinit var repository: MyRepository
#BeforeEach
fun setUp() {
client = mock(WebClient::class.java)
repository = MyRepository(client)
}
#Test
fun getError() {
assertThrows(WebClientResponseException::class.java, {
client.mockAndThrow()
repository.get("x")
})
}
#Test
fun get() {
val myType = MyType()
client.mockAndReturn(myType)
assertEquals(myType, repository.get("x").block())
}
}
Note: tests on JUnit 5
This will be supported in a future Spring Framework version with MockRestServiceServer; see SPR-15286