You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Nov 14, 2024. It is now read-only.
@@ -61,6 +66,8 @@ We can start implementing the use case now that we have set up. Since we are dil
61
66
First, we want to test the happy path, meaning the use case creates a new portfolio for the user. We need to implement our use case interface with a concrete class, which we usually call a service:
@@ -72,8 +79,9 @@ As you might have noticed, the `createPortfolioUseCase` method is nothing more t
72
79
We'll use different testing frameworks. Let's begin with a setup that should be familiar to developers addicted to Kotlin and Spring: **JUnit 5 as the test runtime and AssertJ for assertions**.
73
80
74
81
```kotlin
82
+
importkotlin.test.Test
83
+
75
84
internalclassCreatePortfolioUseCaseJUnit5Test {
76
-
77
85
privateval underTest = createPortfolioUseCase()
78
86
79
87
@Test
@@ -89,6 +97,9 @@ Now, we have to test that, given some inputs, the function will return the expec
89
97
However, the below implementation will not even compile:
90
98
91
99
```kotlin
100
+
importarrow.core.Either
101
+
importarrow.core.raise.either
102
+
92
103
@Test
93
104
internalfun`given a userId and an initial amount, when executed, then it create the portfolio`() {
94
105
val actualResult:PortfolioId=
@@ -152,7 +163,8 @@ Now, we can implement the function `createPortfolio` to make the test pass. Let'
@@ -161,13 +173,15 @@ If we run our test, it should be green.
161
173
Instead of transforming the `Raise<E>.() -> A` function in a `() -> Either<E, A>` function, **we can use the `fold` function provided by the Arrow library**:
162
174
163
175
```kotlin
176
+
importorg.assertj.core.api.Assertions
177
+
164
178
@Test
165
179
internalfun`given a userId and an initial amount, when executed, then it create the portfolio (using fold)`() {
@@ -178,6 +192,9 @@ internal fun `given a userId and an initial amount, when executed, then it creat
178
192
However, the above code is cumbersome and less readable than the previous one. Moreover, we must apply a `fold` function whenever we want to test a function declared in a `Raise<E>` context. Fortunately, the `assertj-arrow-core` does it for us, defining some handful of assertions that use the `fold` function under the hood:
179
193
180
194
```kotlin
195
+
import`in`.rcard.assertj.arrowcore.RaiseAssert
196
+
197
+
181
198
@Test
182
199
internalfun`given a userId and an initial amount, when executed, then it create the portfolio (using RaiseAssert)`() {
183
200
RaiseAssert
@@ -198,11 +215,15 @@ The test is less readable than the one with the `either` builder because the lib
198
215
199
216
We have used JUnit 5 until now. However, we can switch to Kotest. **Kotest is a robust testing framework for Kotlin**, which is very close to ScalaTest for the Scala language. Kotest also has a set of tailored assertions for some of the available types in the Arrow library (see the [documentation](https://kotest.io/docs/assertions/arrow.html) for further details).
200
217
201
-
So, let's translate the above tests in Kotest notation.
218
+
If you're writing code in IntelliJ IDEA, it might be worth installing the Kotest plugin to be able to run the tests directly in the IDE.
219
+
220
+
So, let's translate the above tests in [Kotest](https://plugins.jetbrains.com/plugin/14080-kotest-plugin-intellij) notation.
@@ -324,52 +345,25 @@ There are a lot of libraries that can help us to create mocks. The most famous i
324
345
**Mocking a dependency is a three-step process**. First, you need to retrieve from the library an empty mock of the dependency:
325
346
326
347
```kotlin
348
+
importio.mockk.mockk
349
+
327
350
val countUserPortfoliosMock:CountUserPortfoliosPort= mockk()
328
351
```
329
352
330
353
The `mockk()` factory function provides a proxy to the port we can use to instrument our needs. The second step is the instrumentation of the mock indeed, and we should instrument the `countUserPortfoliosMock` in the following way:
every { countUserPortfoliosMock.countByUserId(UserId("bob")) } returns 0
338
357
```
339
358
340
-
The above code translates to the following sentence: "Every time we call the method `countByUserId` of the instance `countUserPortfoliosMock` with input equals to `UserId("bob")`, we'll get the value `0` as a result.". Despite that, we get an error if we try to compile it:
341
-
342
-
```
343
-
No context receiver for 'arrow.core.raise.Raise<in.rcard.arrow.raise.testing.DomainError>' found.
344
-
```
345
-
346
-
The compiler tells the truth. We defined the `countByUserId` function using the `Raise<DomainError>` context. We should remember that **declaring a context receiver is like adding an implicit input parameter to the list of explicitly declared input parameters**. So, the compiler tells us we're not giving enough parameters for the function to be mocked.
347
-
348
-
We need to add the missing parameter with a matcher, as with any other input parameter. The only difference is that we need the `Raise<DomainError>` at the scope level. Then, we can use the `with` scope function once again:
349
-
350
-
```kotlin
351
-
every {
352
-
with(any<Raise<DomainError>>()) {
353
-
with(countUserPortfoliosMock) {
354
-
countByUserId(UserId("bob"))
355
-
}
356
-
}
357
-
} returns 0
358
-
```
359
-
360
-
Now, the compiler is happier, and we can proceed with the rest of the test code:
359
+
Then, we can proceed with the rest of the test code:
361
360
362
361
```kotlin
363
362
should("create a portfolio for a user (using mockk") {
364
363
val countUserPortfoliosMock:CountUserPortfoliosPort= mockk()
365
364
val underTestWithMock = createPortfolioUseCase(countUserPortfoliosMock)
366
-
every {
367
-
with(any<Raise<DomainError>>()) {
368
-
with(countUserPortfoliosMock) {
369
-
countByUserId(UserId("bob"))
370
-
}
371
-
}
372
-
} returns 0
365
+
every { countUserPortfoliosMock.countByUserId(UserId("bob")) } returns 0
366
+
373
367
val actualResult:Either<DomainError, PortfolioId> =
374
368
either {
375
369
with(underTestWithMock) {
@@ -446,6 +440,8 @@ The above test verifies the behavior of the use case when there was an unexpecte
446
440
For completeness, we can translate the above test using Mockito to understand the differences between the two libraries. In detail, we'll use the library `mockito-kotlin` on top of Mockito to have a more idiomatic look and feel:
447
441
448
442
```kotlin
443
+
importorg.mockito.kotlin.*
444
+
449
445
@Test
450
446
fun`given a userId and an initial amount, when executed with error, then propagates the error properly`() {
0 commit comments