Common test assertions and utilities for Kotlin multiplatform projects
—
Core utility functions for test execution and expectation validation. These functions provide additional testing capabilities beyond standard assertions, including expectation validation, test failure marking, and placeholder test implementation.
Validates that a code block returns an expected value, providing a concise way to test function results.
/**
* Asserts that the given function block returns the expected value.
* @param expected The value that the block should return
* @param block The function to execute and validate
* @throws AssertionError if the block returns a different value
*/
fun <T> expect(expected: T, block: () -> T)
/**
* Asserts that the given function block returns the expected value with a custom message.
* @param expected The value that the block should return
* @param message Optional message to show if assertion fails
* @param block The function to execute and validate
* @throws AssertionError if the block returns a different value
*/
fun <T> expect(expected: T, message: String?, block: () -> T)Usage Examples:
import kotlin.test.expect
@Test
fun testExpectFunction() {
// Basic expectation testing
expect(10) { 5 + 5 }
expect("hello") { "hel" + "lo" }
expect(true) { 10 > 5 }
// Complex function testing
expect(42) {
val calculator = Calculator()
calculator.add(40, 2)
}
// With custom messages
expect(100, "Score calculation should return 100") {
gameLogic.calculateFinalScore()
}
// Testing object methods
val user = User("Alice", 25)
expect("Alice") { user.getName() }
expect(25) { user.getAge() }
// Collection operations
expect(3) { listOf(1, 2, 3).size }
expect("HELLO") { "hello".uppercase() }
}
@Test
fun testComplexExpectations() {
// Testing with side effects
val counter = Counter()
expect(1) { counter.increment() }
expect(2) { counter.increment() }
expect(0) { counter.reset(); counter.getValue() }
// API call testing
val apiClient = TestApiClient()
expect(200) { apiClient.getStatus("/health").statusCode }
expect("OK") { apiClient.getStatus("/health").message }
// Conditional logic testing
expect("adult") {
val person = Person(age = 25)
if (person.age >= 18) "adult" else "minor"
}
}Explicitly marks a test as failed with an optional message and cause.
/**
* Marks a test as failed with the specified message.
* This function never returns normally - it always throws.
* @param message Optional failure message
* @return Nothing (this function never returns)
* @throws AssertionError always
*/
fun fail(message: String? = null): Nothing
/**
* Marks a test as failed with the specified message and underlying cause.
* This function never returns normally - it always throws.
* @param message Optional failure message
* @param cause Optional underlying cause of the failure
* @return Nothing (this function never returns)
* @throws AssertionError always
* @since Kotlin 1.4
*/
fun fail(message: String? = null, cause: Throwable? = null): NothingUsage Examples:
import kotlin.test.fail
@Test
fun testFailFunction() {
val condition = checkSomeCondition()
if (!condition) {
fail("Expected condition to be true but it was false")
}
// Unreachable code after fail()
println("This will never execute")
}
@Test
fun testConditionalFailure() {
val result = performComplexOperation()
when (result.status) {
Status.SUCCESS -> {
// Test passes, continue validation
assertTrue(result.data.isNotEmpty())
}
Status.ERROR -> {
fail("Operation failed with error: ${result.errorMessage}")
}
Status.UNKNOWN -> {
fail("Operation returned unknown status")
}
}
}
@Test
fun testFailWithCause() {
try {
val service = ExternalService()
service.performOperation()
} catch (e: ServiceException) {
fail("Service operation should not throw exception", e)
} catch (e: Exception) {
fail("Unexpected exception occurred", e)
}
}
@Test
fun testValidationFailure() {
val data = loadTestData()
// Explicit validation with meaningful failure messages
if (data.isEmpty()) {
fail("Test data should not be empty")
}
if (data.size < 10) {
fail("Test data should contain at least 10 items, but got ${data.size}")
}
// Continue with normal test logic
assertTrue(data.all { it.isValid() })
}Marks a test as a TODO placeholder that should not be executed yet.
/**
* Takes a block of test code and doesn't execute it.
* Used to mark tests that are not yet implemented or should be skipped.
* This is an expect declaration that has platform-specific implementations.
* @param block The test code that should not be executed
*/
fun todo(block: () -> Unit)Usage Examples:
import kotlin.test.todo
import kotlin.test.Test
class UserServiceTest {
@Test
fun testCreateUser() {
// Implemented test
val service = UserService()
val user = service.createUser("Alice", "alice@example.com")
assertEquals("Alice", user.name)
}
@Test
fun testUpdateUser() {
todo {
// This test is not yet implemented
// The block won't execute but the test will be reported as TODO
val service = UserService()
val user = service.updateUser(1, "Bob", "bob@example.com")
assertEquals("Bob", user.name)
}
}
@Test
fun testDeleteUser() {
todo {
// Placeholder for future test implementation
val service = UserService()
service.deleteUser(1)
assertNull(service.findUser(1))
}
}
@Test
fun testComplexUserOperation() {
todo {
// This test requires complex setup that's not ready yet
val service = UserService()
val database = TestDatabase.setup()
val cache = TestCache.setup()
// Complex test logic here...
val result = service.performComplexOperation()
assertTrue(result.isSuccess)
}
}
}
class IntegrationTest {
@Test
fun testBasicIntegration() {
// Working integration test
val client = ApiClient()
val response = client.ping()
assertEquals(200, response.status)
}
@Test
fun testAdvancedIntegration() {
todo {
// This integration test needs external service setup
val client = ApiClient()
val externalService = ExternalService.connect()
val result = client.performIntegration(externalService)
assertTrue(result.isSuccess)
}
}
}Use expect for concise single-expression testing, assertEquals for explicit value comparison:
// Use expect for concise testing
expect(5) { list.size }
expect("result") { processor.process(input) }
// Use assertEquals for explicit comparison
val actual = processor.process(input)
assertEquals("result", actual)Use fail when standard assertions don't provide appropriate validation:
@Test
fun testCustomValidation() {
val result = complexOperation()
// Custom business logic validation
if (!result.isValid() || result.score < 0) {
fail("Result failed business validation: $result")
}
// Additional standard assertions
assertTrue(result.isComplete())
}Use todo to maintain test structure during development:
class NewFeatureTest {
@Test
fun testImplementedPart() {
// Already working
assertTrue(newFeature.basicFunctionality())
}
@Test
fun testAdvancedPart() {
todo {
// Will implement after basic part is stable
assertTrue(newFeature.advancedFunctionality())
}
}
}AssertionError when the block result doesn't match the expected valueAssertionError with the provided message and optional causeError messages provide clear context for debugging:
// This will throw: AssertionError: Expected <5>, actual <3>.
expect(5) { listOf(1, 2, 3).size }
// This will throw: AssertionError: Custom validation failed
fail("Custom validation failed")Install with Tessl CLI
npx tessl i tessl/maven-org-jetbrains-kotlin--kotlin-test-common