Testing Guidelines
This guide outlines testing guidelines and best practices for TrustWeave.
Overview
TrustWeave testing strategy includes:
Unit Tests – test individual components in isolation
Integration Tests – test component interactions
End-to-End Tests – test complete workflows
Test Utilities – trustweave-testkit for in-memory implementations
Testing Principles
Test Isolation
Each test should be independent:
1
2
3
4
5
6
7
@Test
fun testIsolated () = runBlocking {
// Each test gets its own fixture
val fixture = TrustWeaveTestFixture . builder (). build (). use { fixture ->
// Test code
}
}
Test Naming
Use descriptive test names:
1
2
3
4
@Test
fun testCreateDidWithEd25519Algorithm () = runBlocking {
// ...
}
Test Organization
Organize tests by functionality:
1
2
3
4
5
6
7
8
9
10
11
class DidMethodTest {
@Test
fun testCreateDid () = runBlocking {
// ...
}
@Test
fun testResolveDid () = runBlocking {
// ...
}
}
Unit Testing
Testing DID Methods
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import org.trustweave.testkit.*
import org.trustweave.did.*
import kotlin.test.Test
import kotlin.test.assertNotNull
class DidMethodTest {
@Test
fun testCreateDid () = runBlocking {
val kms = InMemoryKeyManagementService ()
val method = DidKeyMockMethod ( kms )
val options = didCreationOptions {
algorithm = KeyAlgorithm . Ed25519
}
val did = method . createDid ( options )
assertNotNull ( did )
assert ( did . id . startsWith ( "did:key:" ))
}
}
Testing Key Management
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import org.trustweave.testkit.kms.InMemoryKeyManagementService
import org.trustweave.kms.*
import kotlin.test.Test
class KmsTest {
@Test
fun testGenerateAndSign () = runBlocking {
val kms = InMemoryKeyManagementService ()
val key = kms . generateKey ( Algorithm . Ed25519 )
assertNotNull ( key )
val data = "Hello, TrustWeave!" . toByteArray ()
val signature = kms . sign ( key . id , data )
assertNotNull ( signature )
assertEquals ( 64 , signature . size ) // Ed25519 signature size
}
}
Integration Testing
Testing Credential Workflows
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import org.trustweave.testkit.*
import org.trustweave.TrustWeave
import kotlin.test.Test
class CredentialWorkflowTest {
@Test
fun testCredentialIssuanceAndVerification () = runBlocking {
val fixture = TrustWeaveTestFixture . builder ()
. withInMemoryBlockchainClient ( "algorand:testnet" )
. build ()
. use { fixture ->
val TrustWeave = TrustWeave . create ()
// Create issuer DID
val issuerDid = TrustWeave . createDid (). getOrThrow ()
// Issue credential
val credential = TrustWeave . issueCredential (
issuerDid = issuerDid . id ,
issuerKeyId = issuerDid . document . verificationMethod . first (). id ,
credentialSubject = buildJsonObject {
put ( "id" , "did:key:subject" )
put ( "name" , "Alice" )
}
). getOrThrow ()
// Verify credential
val verificationResult = TrustWeave . verifyCredential ( credential ). getOrThrow ()
assert ( verificationResult . valid )
}
}
}
End-to-End Testing
EO Integration Tests
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import org.trustweave.testkit.eo.BaseEoIntegrationTest
import org.trustweave.testkit.anchor.InMemoryBlockchainAnchorClient
import org.trustweave.anchor.*
import kotlin.test.Test
class MyEoIntegrationTest : BaseEoIntegrationTest () {
override fun createAnchorClient (
chainId : String ,
options : Map < String , Any ?>
): BlockchainAnchorClient {
return InMemoryBlockchainAnchorClient ( chainId )
}
@Test
fun testEoScenario () = runBlocking {
val result = runEoTestScenario ()
assert ( result . verificationResult . valid )
}
}
Test Utilities
TrustWeaveTestFixture
Use test fixtures for setup:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import org.trustweave.testkit.*
import kotlin.test.Test
class FixtureTest {
@Test
fun testWithFixture () = runBlocking {
val fixture = TrustWeaveTestFixture . builder ()
. withKms ( InMemoryKeyManagementService ())
. withDidmethod ( KEY ) { DidKeyMockMethod ( it ) }
. withBlockchainClient ( "algorand:testnet" ) {
InMemoryBlockchainAnchorClient ( "algorand:testnet" )
}
. build ()
. use { fixture ->
val issuerDoc = fixture . createIssuerDid ()
assertNotNull ( issuerDoc )
}
}
}
Error Testing
Testing Error Cases
1
2
3
4
5
6
7
8
9
10
11
12
@Test
fun testErrorHandling () = runBlocking {
val kms = InMemoryKeyManagementService ()
val result = kms . sign ( "nonexistent-key" , "data" . toByteArray ())
result . fold (
onSuccess = { fail ( "Expected error" ) },
onFailure = { error ->
assert ( error is TrustWeaveError . KeyNotFound )
}
)
}
Testing Validation
1
2
3
4
5
6
7
8
9
10
11
12
@Test
fun testInvalidInput () = runBlocking {
val method = DidKeyMockMethod ( InMemoryKeyManagementService ())
val result = method . resolveDid ( "invalid-did" )
result . fold (
onSuccess = { fail ( "Expected error" ) },
onFailure = { error ->
assert ( error is TrustWeaveError . DidResolutionFailed )
}
)
}
Best Practices
Resource Cleanup
Always use use {} for cleanup:
1
2
3
4
fixture . use { fixture ->
// Test code
// Automatic cleanup on exit
}
Test Data
Use meaningful test data:
1
2
val issuerDid = "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK"
val subjectDid = "did:key:z6MkhbXBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK"
Assertions
Use descriptive assertions:
1
2
3
4
5
6
7
// Good
assertNotNull ( did , "DID should not be null" )
assertEquals ( "did:key:" , did . id . substring ( 0 , 8 ), "DID should start with did:key:" )
// Less clear
assert ( did != null )
assert ( did . id . startsWith ( "did:key:" ))
Test Coverage
Coverage Goals
Aim for:
Unit Tests – 80%+ coverage
Integration Tests – cover critical paths
End-to-End Tests – cover main workflows
Measuring Coverage
1
./gradlew test jacocoTestReport
Running Tests
All Tests
Specific Module
Specific Test Class
1
./gradlew :common:test --tests "DidMethodTest"
With Verbose Output
Next Steps
References