Marcell-Juhasz / secret-diary

0 stars 1 forks source link

Don't use Thread.Sleep just to test passage of time #7

Closed RedJocker closed 2 years ago

RedJocker commented 2 years ago

Time in Roboletric is emulated you don't need to sleep to pass time.

You will need a shadow from your main looper and then use the method .idleFor() to pass the time

you can see in the new template, updated yesterday, how to get a the shadowLooper https://github.com/hyperskill/android-projects-template/blob/main/Project%20Name/stage1/src/test/java/org/hyperskill/projectname/internals/AbstractUnitTest.kt

The only problem is that solutions using System.currentTimeMillis() or Clock.System.now() wont work, so you have to change your solution and also add this to your description

<p>
    Obs: The passage of time is emulated on test, don't use <code>System.currentTimeMillis()</code>
    or <code>Clock.System.now()</code> because it won't work.
    You can use this alternative instead <code> SystemClock.currentGnssTimeClock().millis()</code>,
</p>

After changing the solution you should be able to remove Thread.sleep and pass time using .idleFor() for any amount of time desired

RedJocker commented 2 years ago

just realized that SystemClock.currentGnssTimeClock().millis() requires min api 29, so it is not a good solution. I have another project that depends on time too, so I will work on this issue and see what can be done to avoid Thread.sleep

RedJocker commented 2 years ago

ok, I was able to create a custom shadow class that intercepts calls to Clock.System.now(), I will send a pull request with this and some other easy alterations from other raised issues.

But System.currentTimeMilles() will still not work so we will still need to have an observation about that on description. Intercepting java.lang code seems to much more complicated https://stackoverflow.com/questions/31659771/robolectric-3-0-mocking-system-currenttimemillis

https://github.com/robolectric/robolectric/issues/1786

RedJocker commented 2 years ago

sent the pull request with the shadow, please test it and accept it if it is all ok. Left issue #9 unsolved because I think it is better for you to decide how much time should be passing on each of this calls, but it can be any amount of time, days, months, years, whatever.

One note, on tests the time will always start in the "origin of time" which is midnight, January 1, 1970 UTC. Unfortunately it will still depend on locale so it might rewind to the end of 1969 for example depending on your timezone. If it didn't depend on locale you could hardcode your expected test variables.

RedJocker commented 2 years ago

this is mostly solved with pull request #11, but it is good to give a better attention to emulation of time to see if it is according to what you expect it to be for your tests.

this is also related with issue #9

Marcell-Juhasz commented 2 years ago

In stage3 you've made a change: REMOVED: Thread.sleep(3000) ADDED: shadowLooper.idleFor(Duration.ofSeconds(300_000))

Maybe you meant to write 3 seconds instead of 300,000, not? Or the 300,000 seconds will be emulated and the test will run in a few seconds?

RedJocker commented 2 years ago

No I left it there purposefully, but it was just to show that it can be any amount of time you want. You can choose how much you actually want. Tests will run as fast as it takes to process the instructions, there won't be any slepping

Marcell-Juhasz commented 2 years ago

done