How to unit test coroutine when it contains coroutine delay?
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 |
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 |
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 '18 at 0:02
asked Nov 12 '18 at 23:34
Cody
2,47822829
2,47822829
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
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 '18 at 0:20
1
with async for example
– s1m0nw1
Nov 13 '18 at 0:36
add a comment |
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 |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
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
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
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 '18 at 0:20
1
with async for example
– s1m0nw1
Nov 13 '18 at 0:36
add a comment |
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 '18 at 0:20
1
with async for example
– s1m0nw1
Nov 13 '18 at 0:36
add a comment |
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 '18 at 0:36
answered Nov 13 '18 at 0:08
s1m0nw1
25.3k641101
25.3k641101
Is there a way to not including the specific delay number in the test?
– Cody
Nov 13 '18 at 0:20
1
with async for example
– s1m0nw1
Nov 13 '18 at 0:36
add a comment |
Is there a way to not including the specific delay number in the test?
– Cody
Nov 13 '18 at 0:20
1
with async for example
– s1m0nw1
Nov 13 '18 at 0:36
Is there a way to not including the specific delay number in the test?
– Cody
Nov 13 '18 at 0:20
Is there a way to not including the specific delay number in the test?
– Cody
Nov 13 '18 at 0:20
1
1
with async for example
– s1m0nw1
Nov 13 '18 at 0:36
with async for example
– s1m0nw1
Nov 13 '18 at 0:36
add a comment |
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 |
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 |
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 '18 at 9:48
Marko Topolnik
145k19194322
145k19194322
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
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