From 127cc88858a670c7d9c8d384aa1d4a09426bb8fb Mon Sep 17 00:00:00 2001 From: Alexey Kiselev Date: Mon, 9 May 2022 23:53:29 +0300 Subject: [PATCH 1/2] coroutines example unit test --- .../vk/lection09/CoroutinesExampleUnitTest.kt | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 lection09/app/src/test/java/company/vk/lection09/CoroutinesExampleUnitTest.kt diff --git a/lection09/app/src/test/java/company/vk/lection09/CoroutinesExampleUnitTest.kt b/lection09/app/src/test/java/company/vk/lection09/CoroutinesExampleUnitTest.kt new file mode 100644 index 0000000..1c0272f --- /dev/null +++ b/lection09/app/src/test/java/company/vk/lection09/CoroutinesExampleUnitTest.kt @@ -0,0 +1,102 @@ +package company.vk.lection09 + +import kotlinx.coroutines.* +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock +import org.junit.Assert +import org.junit.Test +import java.io.ByteArrayOutputStream +import java.io.PrintStream + +@ExperimentalCoroutinesApi +class CoroutinesExampleUnitTest { + + private suspend fun originalImplementation(delayInMillis: Long = 1000) { + val dispatcher = Dispatchers.Default + .limitedParallelism(1) + var counter = 0 + GlobalScope.launch { + repeat(100) { + launch(dispatcher) { + val oldCounter = counter++ + delay(delayInMillis) + println("$oldCounter and ${counter++}") + } + } + }.join() + } + + private suspend fun fixedImplementation(delayInMillis: Long = 1000) { + val dispatcher = Dispatchers.Default + .limitedParallelism(1) + + var counter = 0 + val counterMutex = Mutex() + GlobalScope.launch { + repeat(100) { + launch(dispatcher) { + counterMutex.withLock { + val oldCounter = counter++ + delay(delayInMillis) + println("$oldCounter and ${counter++}") + } + } + } + }.join() + } + + @Test + fun originalImplementationTest() { + val result = doWithMockOutStream { + runBlocking { + originalImplementation() + } + } + Assert.assertNotEquals(expectedForWorkImpl(), result) + } + + @Test + fun originalImplementationWithAnotherExpectedTest() { + val result = doWithMockOutStream { + runBlocking { + originalImplementation() + } + } + Assert.assertEquals(expectedForWrongImpl(), result) + } + + @Test + fun fixedImplementationTest() { + val result = doWithMockOutStream { + runBlocking { + fixedImplementation(delayInMillis = 10) + } + } + Assert.assertEquals(expectedForWorkImpl(), result) + } + + private fun expectedForWorkImpl(): String { + val expected = StringBuilder() + for (i in 0 until 200 step 2) { + expected.append("$i and ${i + 1}\n") + } + return expected.toString() + } + + private fun expectedForWrongImpl(): String { + val expected = StringBuilder() + for (i in 0 until 100) { + expected.append("$i and ${i + 100}\n") + } + return expected.toString() + } + + private fun doWithMockOutStream(action: () -> Unit): String { + val consoleStream = System.out + val byteArrayOutStream = ByteArrayOutputStream() + System.setOut(PrintStream(byteArrayOutStream)) + action.invoke() + System.setOut(consoleStream) + return byteArrayOutStream.toString() + } +} From 8fddf3896322ebd268f030bf9e23709ed514bfa2 Mon Sep 17 00:00:00 2001 From: Alexey Kiselev Date: Wed, 11 May 2022 19:57:30 +0300 Subject: [PATCH 2/2] coroutines-test in coroutines example unit test --- lection09/app/build.gradle | 1 + .../vk/lection09/CoroutinesExampleUnitTest.kt | 118 ++++++++++-------- 2 files changed, 65 insertions(+), 54 deletions(-) diff --git a/lection09/app/build.gradle b/lection09/app/build.gradle index bac46e7..486ccce 100644 --- a/lection09/app/build.gradle +++ b/lection09/app/build.gradle @@ -98,6 +98,7 @@ dependencies { testImplementation 'junit:junit:4.+' testImplementation "io.mockk:mockk:1.12.3" + testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.1' androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' diff --git a/lection09/app/src/test/java/company/vk/lection09/CoroutinesExampleUnitTest.kt b/lection09/app/src/test/java/company/vk/lection09/CoroutinesExampleUnitTest.kt index 1c0272f..32214e5 100644 --- a/lection09/app/src/test/java/company/vk/lection09/CoroutinesExampleUnitTest.kt +++ b/lection09/app/src/test/java/company/vk/lection09/CoroutinesExampleUnitTest.kt @@ -3,87 +3,98 @@ package company.vk.lection09 import kotlinx.coroutines.* import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock +import kotlinx.coroutines.test.runTest +import org.junit.After import org.junit.Assert +import org.junit.Before import org.junit.Test import java.io.ByteArrayOutputStream import java.io.PrintStream +interface Counter { + + suspend fun increaseCounterAndPrintAsync() +} + @ExperimentalCoroutinesApi -class CoroutinesExampleUnitTest { +class OriginCounter( + private val scope: CoroutineScope +) : Counter { + + private var counter = 0 - private suspend fun originalImplementation(delayInMillis: Long = 1000) { - val dispatcher = Dispatchers.Default - .limitedParallelism(1) - var counter = 0 - GlobalScope.launch { + override suspend fun increaseCounterAndPrintAsync() { + scope.launch { repeat(100) { - launch(dispatcher) { + launch { val oldCounter = counter++ - delay(delayInMillis) + delay(1000L) println("$oldCounter and ${counter++}") } } }.join() } +} + +@ExperimentalCoroutinesApi +class MutexCounter( + private val scope: CoroutineScope +) : Counter { + + private val mutex = Mutex() - private suspend fun fixedImplementation(delayInMillis: Long = 1000) { - val dispatcher = Dispatchers.Default - .limitedParallelism(1) + private var counter = 0 - var counter = 0 - val counterMutex = Mutex() - GlobalScope.launch { + override suspend fun increaseCounterAndPrintAsync() { + scope.launch { repeat(100) { - launch(dispatcher) { - counterMutex.withLock { + launch { + mutex.withLock { val oldCounter = counter++ - delay(delayInMillis) + delay(1000L) println("$oldCounter and ${counter++}") } } } }.join() } +} - @Test - fun originalImplementationTest() { - val result = doWithMockOutStream { - runBlocking { - originalImplementation() - } - } - Assert.assertNotEquals(expectedForWorkImpl(), result) +@ExperimentalCoroutinesApi +class CoroutinesExampleUnitTest { + + private val printStreamByteArray = ByteArrayOutputStream() + private val mockPrintStream = PrintStream(printStreamByteArray) + private val consolePrintStream = System.out + + @Before + fun before() { + System.setOut(mockPrintStream) } - @Test - fun originalImplementationWithAnotherExpectedTest() { - val result = doWithMockOutStream { - runBlocking { - originalImplementation() - } - } - Assert.assertEquals(expectedForWrongImpl(), result) + @After + fun after() { + printStreamByteArray.reset() + System.setOut(consolePrintStream) } @Test - fun fixedImplementationTest() { - val result = doWithMockOutStream { - runBlocking { - fixedImplementation(delayInMillis = 10) - } - } - Assert.assertEquals(expectedForWorkImpl(), result) + fun originalCounterTest() = runTest { + OriginCounter(this) + .increaseCounterAndPrintAsync() + val result = printStreamByteArray.toString() + Assert.assertEquals(expectedForOriginalImpl(), result) } - private fun expectedForWorkImpl(): String { - val expected = StringBuilder() - for (i in 0 until 200 step 2) { - expected.append("$i and ${i + 1}\n") - } - return expected.toString() + @Test + fun mutexCounterTest() = runTest { + MutexCounter(this) + .increaseCounterAndPrintAsync() + val result = printStreamByteArray.toString() + Assert.assertEquals(expectedForMutexImpl(), result) } - private fun expectedForWrongImpl(): String { + private fun expectedForOriginalImpl(): String { val expected = StringBuilder() for (i in 0 until 100) { expected.append("$i and ${i + 100}\n") @@ -91,12 +102,11 @@ class CoroutinesExampleUnitTest { return expected.toString() } - private fun doWithMockOutStream(action: () -> Unit): String { - val consoleStream = System.out - val byteArrayOutStream = ByteArrayOutputStream() - System.setOut(PrintStream(byteArrayOutStream)) - action.invoke() - System.setOut(consoleStream) - return byteArrayOutStream.toString() + private fun expectedForMutexImpl(): String { + val expected = StringBuilder() + for (i in 0 until 200 step 2) { + expected.append("$i and ${i + 1}\n") + } + return expected.toString() } }