This use case validates credentials and delegates to the repository.
class LoginUseCaseTest { private val userRepository = TestUserRepository().also { it.expectedLoginRequest = VALID_LOGIN_REQUEST } private val sut = LoginUseCase(userRepository) @Test fun `EXPECT invalid email error WHEN login request has invalid email`() = runTest { val loginRequestWithInvalidEmail = LoginRequest("", "validPassword") val result = sut(loginRequestWithInvalidEmail) assertEquals(Answer.Error(LoginError.InvalidEmail), result) } @Test fun `EXPECT invalid password error WHEN login request has invalid password`() = runTest { val loginRequestWithInvalidPassword = LoginRequest("[email protected]", "") val result = sut(loginRequestWithInvalidPassword) assertEquals(Answer.Error(LoginError.InvalidPassword), result) } @Test fun `EXPECT success WHEN login request is valid and repository returns success`() = runTest { val repositoryResult = Answer.Success(Unit) userRepository.loginResult = repositoryResult val result = sut(VALID_LOGIN_REQUEST) assertEquals(repositoryResult, result) } @Test fun `EXPECT error WHEN login request is valid and repository returns error`() = runTest { val repositoryResult = Answer.Error(LoginError.GenericError) userRepository.loginResult = repositoryResult val result = sut(VALID_LOGIN_REQUEST) assertEquals(repositoryResult, result) } private companion object { val VALID_LOGIN_REQUEST = LoginRequest("[email protected]", "validPassword") }}
Suspend functions are tested using runTest from kotlinx-coroutines-test, which provides a controlled test environment for coroutines.
Use cases that return Flow are tested using the FlowTestObserver utility.
class ObserveUserCartUseCaseTest { private val testCartRepository = TestCartRepository() private val sut = ObserveUserCartUseCase({ USER }, testCartRepository) @Test fun `EXPECT cart updates`() { testCartRepository.cartUpdates[USER_ID] = flowOf(Cart(emptyList()), Cart(CART_ITEMS)) val testObserver = sut().test() assertEquals( listOf(Cart(emptyList()), Cart(CART_ITEMS)), testObserver.getValues() ) } private companion object { const val USER_ID = "1234" val USER = User(USER_ID, "") val CART_ITEMS = listOf(makeCartItem()) }}
The .test() extension function creates a FlowTestObserver that collects all emitted values for assertion.
class CartTest { @Test fun `EXPECT null subtotal and currency WHEN cart is empty`() { val sut = Cart(emptyList()) val result = sut.getSubtotal() assertNull(result) } @Test fun `EXPECT sum of product per their quantity WHEN cart is not empty`() { val sut = Cart( listOf( makeCartItem(0.99, 1), makeCartItem(25.00, 3), makeCartItem(30.00, 2), makeCartItem(15.00, 1) ) ) val result = sut.getSubtotal() assertEquals(Money(150.99, "$"), result) } @Test fun `EXPECT 0 items WHEN cart is empty`() { val sut = Cart(emptyList()) val result = sut.getNumberOfItems() assertEquals(0, result) } @Test fun `EXPECT number of items x their quantity WHEN items have quantity 1+`() { val sut = Cart(listOf(makeCartItem(quantity = 4), makeCartItem(quantity = 5))) val result = sut.getNumberOfItems() assertEquals(9, result) }}
class EmailTest { @Test fun `EXPECT invalid email WHEN no text entered`() { val result = Email("").isValid() assertFalse(result) } @Test fun `EXPECT invalid email WHEN blank text entered`() { val result = Email(" ").isValid() assertFalse(result) } @Test fun `EXPECT invalid email WHEN text entered`() { val result = Email("a").isValid() assertFalse(result) } @Test fun `EXPECT invalid email WHEN domain entered`() { val result = Email("test.com").isValid() assertFalse(result) } @Test fun `EXPECT invalid email WHEN at symbol entered`() { val result = Email("test@").isValid() assertFalse(result) } @Test fun `EXPECT valid email WHEN valid email entered`() { val result = Email("[email protected]").isValid() assertTrue(result) }}
Validation logic is tested with multiple invalid cases to ensure robust validation.