Testing Soap Consumer. 'uri' must not be empty - kotlin

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.

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")
}
}

Mockk anonymous class

I'm trying to mock anonymous class created in testInstance Sample:
class SomeClass(val someValue:SomeType) :SomeAnotherClass(){
val anonymousClass = object : AnotherClass{
override anotherMethod() { }
}
override fun someMethod(someValue) = anonymousClass.someMethod(someValue)
}
And test class:
class SomeClassTest {
private val someValue: SomeType = mockk()
private val testInstance = spyk(SomeClass(someValue), recordPrivateCalls = true)
#Test
fun `test method`(){
mockkConstructor(CustomTlsSocketFactory::class)
every { anyConstructed<AnotherClass>().someMethod(someValue) } returns mockk()
testInstance.someMethod(someValue)
verify { anyConstructed<AnotherClass>().someMethod(someValue) }
}
}
And for some reason anonymousClass.someMethod(someValue) is trying to call original method not mockk.
Calling testInstance.anonymousClass.isMock is false

Test case is calling actual method even after mocking the method call in ktor framework (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...
}
}

Dagger Injection into Room Callback - lateinit property has not been initialized error

I am adding a RoomDatabase.Callback() to pre populate my room database on creation.
I am running into an issue of injecting exchangeDao field into my class. When running below i get error: "lateinit property exchangeDao has not been initialized". This is despite it being called in my line "exchangeDao.insertExchangeList(equityExchange!!)".
How can i run the below code to pre-populate the database?
private fun buildDatabase(app: Application) =
Room.databaseBuilder(
app,
AppDatabase::class.java,
"your database name"
)
.addCallback(PrePopulateDatabase)
.allowMainThreadQueries()
.build()
Blockquote
object PrePopulateDatabase : RoomDatabase.Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
CoroutineScope(Dispatchers.IO).launch() {
val myClass = MyClass()
}
}
Blockquote
class MyClass {
#Inject
lateinit var exchangeDao: ExchangeDao
init {
updateExchangeEntity(exchangeDao)
}
companion object {
private fun updateExchangeEntity(
exchangeDao: ExchangeDao,
) {
var equityExchange: List<ExchangeResponse.Exchange>? = null
/////////////////////////////////////////////////////////retrofit object
val retrofit = Retrofit.Builder()
.baseUrl("https://api.twelvedata.com/")
.addConverterFactory(GsonConverterFactory.create())
.build()
val myAPICall = retrofit.create(APICall::class.java)
///////////////////////////////////////////////////////make call
val call1 = myAPICall.getEquityInstruments("NASDAQ")
var response1: Response<ExchangeResponse?>? = null
try {
response1 = call1!!.execute()
} catch (e: Exception) {
e.printStackTrace()
}
equityExchange = response1!!.body()!!.data
exchangeDao.insertExchangeList(equityExchange!!)
}
}
}
I needed to run MyClass as a service. This enabled me to add #AndroidEntryPoint and use dagger hilt injection. Don't forget to add the new service into the Manifest file.
#AndroidEntryPoint
class MyClass: Service() {
#Inject
lateinit var exchangeDao: ExchangeDao
}

Async Execution in WebFilter

How can I call the method which return Mono<> and use it to call web method itself?
#Component
class SampleWebFilter(private val sampleService: SampleService) : WebFilter {
override fun filter(exchange: ServerWebExchange, chain: WebFilterChain): Mono<Void> {
val accessToken =
exchange.request.headers["Authorization"]?.firstOrNull()
?: throw IllegalArgumentException("Access token must not be empty")
val res = sampleService.authorize(accessToken)
val id = res.block()?.userId
exchange.attributes["UserId"] = userId
return chain.filter(exchange)
}
}
#Component
interface SampleService {
#GET("/user")
fun authorize(accessToken): Mono<User>
}
the code above throw exception
block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-nio-2
I know we shouldn't block the thread on netty but how can I use id from the SampleService to call web method.
Thanks in advance.
#Component
class SampleWebFilter(private val sampleService: SampleService) : WebFilter {
override fun filter(exchange: ServerWebExchange, chain: WebFilterChain): Mono<Void> {
val accessToken =
exchange.request.headers["Authorization"]?.firstOrNull()
?: throw IllegalArgumentException("Access token must not be empty")
val res = sampleService.authorize(accessToken)
return res.doOnNext {
exchange.attributes["UserId"] = userId
}
.then(chain.filter(exchange))
}}
#Component
interface SampleService {
#GET("/user")
fun authorize(accessToken): Mono<User>
}
I solved the problem writing like above.