Cardano Smart Contract Testing
Scalus provides comprehensive testing tools for Cardano smart contracts — unit testing, debugging, and local execution environments.
Testing Tools Overview
| Tool | Purpose | Best For |
|---|---|---|
| Unit Testing | Property-based tests with ScalaCheck | Validator logic verification |
| Debugging | IDE debugging, logging, error traces | Finding and fixing bugs |
| Emulator | In-memory Cardano node | Fast iteration, CI/CD |
| Local Devnet | Docker-based real Cardano node | Integration tests, pre-deployment |
Unit Testing with ScalaCheck
Write property-based tests using ScalaCheck to verify validator logic:
class MyValidatorTest extends AnyFunSuite with ScalusTest {
test("validator accepts valid signature") {
val txInfo = random[TxInfo]
val signer = random[PubKeyHash]
// Test your validator logic
}
}See Unit Testing for complete guide.
Debugging
Debug validators as regular Scala code — use IDE breakpoints, step through execution, and inspect variables:
@Compile
object MyValidator extends Validator:
inline override def spend(...): Unit = {
log("Starting validation")
val owner = datum.getOrFail("No datum").to[PubKeyHash]
// Set breakpoint here, inspect variables
require(tx.signatories.contains(owner), "Not signed")
}See Debugging for IDE setup and logging.
Local Execution Environments
Emulator — Fast In-Memory Testing
The Emulator validates transactions and executes Plutus scripts instantly — no Docker required:
val emulator = Emulator.withAddresses(Seq(Alice.address, Bob.address))
val tx = TxBuilder(testEnv)
.payTo(Bob.address, Value.ada(10))
.complete(emulator, Alice.address)
.await()
.sign(Alice.signer)
.transaction
emulator.submit(tx).await() // Instant validation + script executionLocal Devnet — Real Cardano Node
Local Devnet runs a real Cardano node (Yaci DevKit) in Docker:
class MyTest extends AnyFunSuite with YaciDevKit {
test("submit transaction to local devnet") {
val ctx = createTestContext()
val tx = TxBuilder(ctx.cardanoInfo)
.payTo(recipient, Value.ada(10))
.complete(ctx.provider, ctx.address)
.await(30.seconds)
.sign(ctx.signer)
.transaction
ctx.submitTx(tx) // Real Cardano node validation
}
}Recommended Workflow
Test pyramid: Tests → Emulator → Local Devnet → Testnet → Mainnet
Development: Write code → Run tests → Emulator → Fast feedback → Debug with IDE
Pre-deployment: All tests pass → Local Devnet → Deploy with confidence
See Also
- Unit Testing — Property-based testing with ScalaCheck
- Debugging — IDE debugging and logging
- Emulator — In-memory testing with instant feedback
- Local Devnet — Integration testing with real Cardano node
- Ledger Rules — Validation rules used by testing tools
Related
- Smart Contracts — Write validators to test
- Security — Security testing considerations
- DApp Starter Tutorial — Complete testing example