How to unit test coroutine when it contains coroutine delay?
up vote
1
down vote
favorite
When I add a coroutine delay() in my view model, the remaining part of the code will not be executed.
This is my demo code:
class SimpleViewModel : ViewModel(), CoroutineScope {
override val coroutineContext: CoroutineContext
get() = Dispatchers.Unconfined
var data = 0
fun doSomething() {
launch {
delay(1000)
data = 1
}
}
}
class ScopedViewModelTest {
@Test
fun coroutineDelay() {
// Arrange
val viewModel = SimpleViewModel()
// ActTes
viewModel.doSomething()
// Assert
Assert.assertEquals(1, viewModel.data)
}
}
I got the assertion result:
java.lang.AssertionError:
Expected :1
Actual :0
Any idea how to fix this?
android unit-testing kotlin coroutine kotlinx.coroutines
add a comment |
up vote
1
down vote
favorite
When I add a coroutine delay() in my view model, the remaining part of the code will not be executed.
This is my demo code:
class SimpleViewModel : ViewModel(), CoroutineScope {
override val coroutineContext: CoroutineContext
get() = Dispatchers.Unconfined
var data = 0
fun doSomething() {
launch {
delay(1000)
data = 1
}
}
}
class ScopedViewModelTest {
@Test
fun coroutineDelay() {
// Arrange
val viewModel = SimpleViewModel()
// ActTes
viewModel.doSomething()
// Assert
Assert.assertEquals(1, viewModel.data)
}
}
I got the assertion result:
java.lang.AssertionError:
Expected :1
Actual :0
Any idea how to fix this?
android unit-testing kotlin coroutine kotlinx.coroutines
add a comment |
up vote
1
down vote
favorite
up vote
1
down vote
favorite
When I add a coroutine delay() in my view model, the remaining part of the code will not be executed.
This is my demo code:
class SimpleViewModel : ViewModel(), CoroutineScope {
override val coroutineContext: CoroutineContext
get() = Dispatchers.Unconfined
var data = 0
fun doSomething() {
launch {
delay(1000)
data = 1
}
}
}
class ScopedViewModelTest {
@Test
fun coroutineDelay() {
// Arrange
val viewModel = SimpleViewModel()
// ActTes
viewModel.doSomething()
// Assert
Assert.assertEquals(1, viewModel.data)
}
}
I got the assertion result:
java.lang.AssertionError:
Expected :1
Actual :0
Any idea how to fix this?
android unit-testing kotlin coroutine kotlinx.coroutines
When I add a coroutine delay() in my view model, the remaining part of the code will not be executed.
This is my demo code:
class SimpleViewModel : ViewModel(), CoroutineScope {
override val coroutineContext: CoroutineContext
get() = Dispatchers.Unconfined
var data = 0
fun doSomething() {
launch {
delay(1000)
data = 1
}
}
}
class ScopedViewModelTest {
@Test
fun coroutineDelay() {
// Arrange
val viewModel = SimpleViewModel()
// ActTes
viewModel.doSomething()
// Assert
Assert.assertEquals(1, viewModel.data)
}
}
I got the assertion result:
java.lang.AssertionError:
Expected :1
Actual :0
Any idea how to fix this?
android unit-testing kotlin coroutine kotlinx.coroutines
android unit-testing kotlin coroutine kotlinx.coroutines
edited Nov 13 at 0:02
asked Nov 12 at 23:34
Cody
2,43322829
2,43322829
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
up vote
1
down vote
accepted
You start a coroutine which suspends for 1 second before setting data
to 1. Your test just invokes doSomething
but does not wait until data
is actually being set. If you add another, longer delay
, to the test it will, work:
@Test
fun coroutineDelay() = runBlocking {
...
viewModel.doSomething()
delay(1100)
...
}
You can also make the coroutine return a Deferred
which you can wait on:
fun doSomething(): Deferred<Unit> {
return async {
delay(1000)
data = 1
}
}
With await
there's no need to delay your code anymore:
val model = SimpleViewModel()
model.doSomething().await()
Is there a way to not including the specific delay number in the test?
– Cody
Nov 13 at 0:20
1
with async for example
– s1m0nw1
Nov 13 at 0:36
add a comment |
up vote
2
down vote
The first issue in your code is that SimpleViewModel.coroutineContext
has no Job
associated with it. The whole point of making your view model a CoroutineScope
is the ability to centralize the cancelling of all coroutines it starts. So add the job as follows (note the absence of a custom getter):
class SimpleViewModel : ViewModel(), CoroutineScope {
override val coroutineContext = Job() + Dispatchers.Unconfined
var data = 0
fun doSomething() {
launch {
delay(1000)
data = 1
}
}
}
Now your test code can ensure it proceeds to the assertions only after all the jobs your view model launched are done:
class ScopedViewModelTest {
@Test
fun coroutineDelay() {
// Arrange
val viewModel = SimpleViewModel()
// ActTes
viewModel.doSomething()
// Assert
runBlocking {
viewModel.coroutineContext[Job]!!.children.forEach { it.join() }
}
Assert.assertEquals(1, viewModel.data)
}
}
add a comment |
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
1
down vote
accepted
You start a coroutine which suspends for 1 second before setting data
to 1. Your test just invokes doSomething
but does not wait until data
is actually being set. If you add another, longer delay
, to the test it will, work:
@Test
fun coroutineDelay() = runBlocking {
...
viewModel.doSomething()
delay(1100)
...
}
You can also make the coroutine return a Deferred
which you can wait on:
fun doSomething(): Deferred<Unit> {
return async {
delay(1000)
data = 1
}
}
With await
there's no need to delay your code anymore:
val model = SimpleViewModel()
model.doSomething().await()
Is there a way to not including the specific delay number in the test?
– Cody
Nov 13 at 0:20
1
with async for example
– s1m0nw1
Nov 13 at 0:36
add a comment |
up vote
1
down vote
accepted
You start a coroutine which suspends for 1 second before setting data
to 1. Your test just invokes doSomething
but does not wait until data
is actually being set. If you add another, longer delay
, to the test it will, work:
@Test
fun coroutineDelay() = runBlocking {
...
viewModel.doSomething()
delay(1100)
...
}
You can also make the coroutine return a Deferred
which you can wait on:
fun doSomething(): Deferred<Unit> {
return async {
delay(1000)
data = 1
}
}
With await
there's no need to delay your code anymore:
val model = SimpleViewModel()
model.doSomething().await()
Is there a way to not including the specific delay number in the test?
– Cody
Nov 13 at 0:20
1
with async for example
– s1m0nw1
Nov 13 at 0:36
add a comment |
up vote
1
down vote
accepted
up vote
1
down vote
accepted
You start a coroutine which suspends for 1 second before setting data
to 1. Your test just invokes doSomething
but does not wait until data
is actually being set. If you add another, longer delay
, to the test it will, work:
@Test
fun coroutineDelay() = runBlocking {
...
viewModel.doSomething()
delay(1100)
...
}
You can also make the coroutine return a Deferred
which you can wait on:
fun doSomething(): Deferred<Unit> {
return async {
delay(1000)
data = 1
}
}
With await
there's no need to delay your code anymore:
val model = SimpleViewModel()
model.doSomething().await()
You start a coroutine which suspends for 1 second before setting data
to 1. Your test just invokes doSomething
but does not wait until data
is actually being set. If you add another, longer delay
, to the test it will, work:
@Test
fun coroutineDelay() = runBlocking {
...
viewModel.doSomething()
delay(1100)
...
}
You can also make the coroutine return a Deferred
which you can wait on:
fun doSomething(): Deferred<Unit> {
return async {
delay(1000)
data = 1
}
}
With await
there's no need to delay your code anymore:
val model = SimpleViewModel()
model.doSomething().await()
edited Nov 13 at 0:36
answered Nov 13 at 0:08
s1m0nw1
23.9k53696
23.9k53696
Is there a way to not including the specific delay number in the test?
– Cody
Nov 13 at 0:20
1
with async for example
– s1m0nw1
Nov 13 at 0:36
add a comment |
Is there a way to not including the specific delay number in the test?
– Cody
Nov 13 at 0:20
1
with async for example
– s1m0nw1
Nov 13 at 0:36
Is there a way to not including the specific delay number in the test?
– Cody
Nov 13 at 0:20
Is there a way to not including the specific delay number in the test?
– Cody
Nov 13 at 0:20
1
1
with async for example
– s1m0nw1
Nov 13 at 0:36
with async for example
– s1m0nw1
Nov 13 at 0:36
add a comment |
up vote
2
down vote
The first issue in your code is that SimpleViewModel.coroutineContext
has no Job
associated with it. The whole point of making your view model a CoroutineScope
is the ability to centralize the cancelling of all coroutines it starts. So add the job as follows (note the absence of a custom getter):
class SimpleViewModel : ViewModel(), CoroutineScope {
override val coroutineContext = Job() + Dispatchers.Unconfined
var data = 0
fun doSomething() {
launch {
delay(1000)
data = 1
}
}
}
Now your test code can ensure it proceeds to the assertions only after all the jobs your view model launched are done:
class ScopedViewModelTest {
@Test
fun coroutineDelay() {
// Arrange
val viewModel = SimpleViewModel()
// ActTes
viewModel.doSomething()
// Assert
runBlocking {
viewModel.coroutineContext[Job]!!.children.forEach { it.join() }
}
Assert.assertEquals(1, viewModel.data)
}
}
add a comment |
up vote
2
down vote
The first issue in your code is that SimpleViewModel.coroutineContext
has no Job
associated with it. The whole point of making your view model a CoroutineScope
is the ability to centralize the cancelling of all coroutines it starts. So add the job as follows (note the absence of a custom getter):
class SimpleViewModel : ViewModel(), CoroutineScope {
override val coroutineContext = Job() + Dispatchers.Unconfined
var data = 0
fun doSomething() {
launch {
delay(1000)
data = 1
}
}
}
Now your test code can ensure it proceeds to the assertions only after all the jobs your view model launched are done:
class ScopedViewModelTest {
@Test
fun coroutineDelay() {
// Arrange
val viewModel = SimpleViewModel()
// ActTes
viewModel.doSomething()
// Assert
runBlocking {
viewModel.coroutineContext[Job]!!.children.forEach { it.join() }
}
Assert.assertEquals(1, viewModel.data)
}
}
add a comment |
up vote
2
down vote
up vote
2
down vote
The first issue in your code is that SimpleViewModel.coroutineContext
has no Job
associated with it. The whole point of making your view model a CoroutineScope
is the ability to centralize the cancelling of all coroutines it starts. So add the job as follows (note the absence of a custom getter):
class SimpleViewModel : ViewModel(), CoroutineScope {
override val coroutineContext = Job() + Dispatchers.Unconfined
var data = 0
fun doSomething() {
launch {
delay(1000)
data = 1
}
}
}
Now your test code can ensure it proceeds to the assertions only after all the jobs your view model launched are done:
class ScopedViewModelTest {
@Test
fun coroutineDelay() {
// Arrange
val viewModel = SimpleViewModel()
// ActTes
viewModel.doSomething()
// Assert
runBlocking {
viewModel.coroutineContext[Job]!!.children.forEach { it.join() }
}
Assert.assertEquals(1, viewModel.data)
}
}
The first issue in your code is that SimpleViewModel.coroutineContext
has no Job
associated with it. The whole point of making your view model a CoroutineScope
is the ability to centralize the cancelling of all coroutines it starts. So add the job as follows (note the absence of a custom getter):
class SimpleViewModel : ViewModel(), CoroutineScope {
override val coroutineContext = Job() + Dispatchers.Unconfined
var data = 0
fun doSomething() {
launch {
delay(1000)
data = 1
}
}
}
Now your test code can ensure it proceeds to the assertions only after all the jobs your view model launched are done:
class ScopedViewModelTest {
@Test
fun coroutineDelay() {
// Arrange
val viewModel = SimpleViewModel()
// ActTes
viewModel.doSomething()
// Assert
runBlocking {
viewModel.coroutineContext[Job]!!.children.forEach { it.join() }
}
Assert.assertEquals(1, viewModel.data)
}
}
answered Nov 16 at 9:48
Marko Topolnik
143k18193320
143k18193320
add a comment |
add a comment |
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53271646%2fhow-to-unit-test-coroutine-when-it-contains-coroutine-delay%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown