updated kotlinx-coroutines-test-jvm-1.6.1.jar and with a lot of changes, it seems I can't clarify how to test exception handling in unit test.
#Test
fun `unblock profile which throws exception`() = runTest {
val vm = createViewModel(StandardTestDispatcher(testScheduler))
val handler = CoroutineExceptionHandler { _, t -> println(t.message) }
coEvery { connectionRepo.patchUnblockMember(FAKE_PROFILE_ID_1) }.throws(
IllegalArgumentException(DummyExceptionStr)
)
launch(testScheduler + handler) {
vm.errorState.collect {
assertThat(it).isIn(1..Int.MAX_VALUE)
return#collect
}
}
vm.unblockContact(fakeBlockedProfile1)
}
but exception is thrown every time, not able to handle it
Related
I tried many references available regarding the same but nothing worked.
I have a method in Kotlin which can throws Checked and unchecked exceptions both(depend on which block in throwing the exception)
fun deleteItem(tokens: List<String>, userId: Long) {
val records = storeRegistry.readItemsByTokens(tokens)
val missingTokens = tokens.toSet() - records.map { it.token }.toSet()
if (missingTokens.isNotEmpty()) {
throw EntityNotFoundException( // checked exception
"Item with tokens=$missingTokens does not exist."
)
}
transactionManager.executeInTransaction {
tokens.forEach {
val success = storeRegistry.deleteItemByToken(it, userId)
if (!success) {
throw InternalException.badRequest( // unchecked exception
"Item delete failed: item token=$it"
)
}
}
}
}
This method is called from some other's class method which is in test. and Unit test look like this
#Test
fun deleteItemShouldThrowIfEntityNotFound() {
whenever(ItemManager.deleteItemsByTokens(any(), any()))
.thenAnswer { throw EntityNotFoundException() }
val deleteRequest = ItemsDeleteRequest.builder()
.ItemsDeleteParams(
listOf(
ItemDeleteParams.createToken("token1"),
ItemDeleteParams.createToken("token2"),
)
).build()
// act
try {
getAfterburner().ignite(
buildServiceRequest(deleteRequest),
DEFAULT_TEST_TIMEOUT
).join()
} catch (e: Exception) {
assert(e.cause is EntityNotFoundException)
}
verify(ItemManager, times(1))
.deleteItemsByTokens(listOf("token1", "token2"), 123456L)
}
When I run above test, I got this error
org.mockito.exceptions.base.MockitoException:
Checked exception is invalid for this method!
Invalid: com.abc.xtz.api.EntityNotFoundException
Mockito won't throw a checked exception for a function that doesn't have the checked exception as part of its signature. To be able to do this, you need to add the checked exception to the function signature using #Throws:
#Throws(EntityNotFoundException::class)
fun deleteItem(tokens: List<String>, userId: Long) {
//...
This is my ViewModel and I want to throw an exception so to catch branch is executed.
class PopularSearchViewModel #Inject constructor(
private val popularSearchUseCase: LoadPopularSearchUseCase,
private val coroutineDispatcherProvider: CoroutineDispatcherProvider
) :
ViewModel() {
private val listOfCatalogProductMutableStateFlow = MutableStateFlow<List<CatalogProduct>>(emptyList())
val listOfCatalogProductStateFlow = listOfCatalogProductMutableStateFlow.asStateFlow()
fun getPopularProducts() {
viewModelScope.launch(coroutineDispatcherProvider.io()) {
try {
listOfCatalogProductMutableStateFlow.value = popularSearchUseCase.execute()
} catch (exception: Exception) {
Timber.e(exception, "popular ${exception.localizedMessage}")
}
}
}
}
This is the actual unit test. In the mock return I am passing an exception. But when running the test I don't think the exception is thrown so the catch block is never executed.
#Test(expected = Exception::class)
fun `should not get popular search products if exception`() {
runBlockingTest {
// Arrange
val listOfEmittedResult = mutableListOf<List<CatalogProduct>>()
val job = launch {
popularSearchViewModel.listOfCatalogProductStateFlow.toList(listOfEmittedResult)
}
whenever(loadPopularSearchUseCase.execute()).thenThrow(Exception("Something bad happened"))
// Act
popularSearchViewModel.getPopularProducts()
// Assert
assertThat(listOfEmittedResult).isEmpty()
verify(loadPopularSearchUseCase).execute()
job.cancel()
}
}
Having an activity which has some functions need to be coverage tested.
class HandlerActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle ) {
System.out.println("enter HandlerActivity.onCreate()")
doSomething(intent)
}
}
//////////////
#RunWith(RobolectricTestRunner::class)
class HandlerActivityTest {
#Test
fun test_activity() {
val conextSpy = spyk(ApplicationProvider.getApplicationContext())
var testEx: Throwable? = null
try {
val intent = Intent(this, HandlerActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
conextSpy.startActivity(intent)
Shadows.shadowOf(Looper.getMainLooper()).idle()
} catch (ex: Throwable) {
testEx = ex
}
junit.framework.Assert.assertNull(testEx)
io.mockk.verify { contextSpy.startActivity(any()) }
}
The test passed, but the HandlerActivity.onCreate() is not called.
How to unit test a onCreate() of an activity?
I have classes
// final class from some library like okhttp
class NetworkCaller {
fun call() {
// performs some real operation
}
fun cancel() {
// .... cancels the request
}
}
class Request {
suspend fun asyncRequest(): String = suspendCancellableCoroutine { continuation ->
val call = NetworkCaller()
continuation.invokeOnCancellation {
call.cancel() // i need to write a test to mock if call.cancel is getting called or not
}
// rest of the code...
}
}
When i am doing
#Test
fun testRequestCancellation() {
val request = Request()
val job = GlobalScope.launch {
val response = request.asyncRequest()
println(response)
}
runBlocking {
job.cancel()
job.join()
}
}
The job is getting cancelled and continuation.invokeOnCancellation() is getting called, i checked with println statements. But i want to mock if the call.cancel method is getting called or not, using mockk library.
I am stuck on this, need help.
In your class, expose the NetworkCaller so it can be switched out for a mock during testing:
class Request(val call: NetworkCaller = NetworkCaller()) {
suspend fun asyncRequest(): String = suspendCancellableCoroutine { continuation ->
continuation.invokeOnCancellation {
call.cancel() // i need to write a test to mock if call.cancel is getting called or not
}
// rest of the code...
}
}
Then you can use mockk in your test:
#Test
fun testRequestCancellation() {
val mockkCall = mockk<NetworkCaller> {
coEvery { cancel() } just Runs
}
val request = Request(mockkCall)
val job = GlobalScope.launch {
val response = request.asyncRequest()
println(response)
}
runBlocking {
job.cancel()
job.join()
}
coVerify { mockkCall.cancel() }
confirmVerified(mockkCall)
}
I have a vertx handler code where I do an executeBlocking but for it to work I need to put in a Thread.sleep() in order for the code in the blocking code to fully execute to the point that I can check the results.
Is there a better way around this so I don't do a Thread.sleep?
My handler code the following is the portion where I only kept the relevant components.
try (final VertxHttpResponse response = new VertxHttpResponse(context)) {
context.vertx().executeBlocking(
future -> {
...
try {
dispatcher.invokePropagateNotFound(request,
response);
future.complete();
} finally {
...
}
}, false,
res -> {
if (res.failed()) {
context.fail(wae);
} else {
if (!context.response().ended()) {
context.response().end();
}
}
});
} catch (final IOException e) {
throw new UncheckedIOException(e);
}
}
My test and the relevant parts
#Test
public void test(final TestContext testContext) throws Exception {
final Router router = Router.router(rule.vertx());
final SpringJaxRsHandler handler = SpringJaxRsHandler.registerToRouter(router, MyApp.class);
final RoutingContext routingContext = mock(RoutingContext.class);
when(routingContext.currentRoute()).thenReturn(router.get("/api/hello"));
when(routingContext.vertx()).thenReturn(rule.vertx());
final HttpServerRequest serverRequest = mock(HttpServerRequest.class);
when(serverRequest.absoluteURI()).thenReturn("/api/hello");
when(serverRequest.isEnded()).thenReturn(true);
when(serverRequest.method()).thenReturn(HttpMethod.GET);
when(routingContext.request()).thenReturn(serverRequest);
final HttpServerResponse response = mock(HttpServerResponse.class);
when(response.putHeader(anyString(), anyString())).thenReturn(response);
when(response.headers()).thenReturn(new VertxHttpHeaders());
when(routingContext.response()).thenReturn(response);
handler.handle(routingContext);
Thread.sleep(1000);
// fails without the sleep above
verify(response, times(1)).setStatusCode(200);
}
I tried
testContext.assertTrue(routingContext.response().ended());
But that returned false.
I refactored the code a bit so I don't use routingContext directly but the concept is still the same. I use Async in combination of a when->then(Answer) and have the async.complete() be called in the Answer. Once that is done do an async.await() to wait for the thread to finish.
final Async async = testContext.async();
when(response.write(Matchers.any(Buffer.class))).then(invocation -> {
try {
return response;
} finally {
async.complete();
}
});
when(serverRequest.response()).thenReturn(response);
router.accept(serverRequest);
async.await();