0
# Framework Implementation
1
2
Framework implementation interface for creating test frameworks that integrate with SBT and support distributed testing in Scala.js environments.
3
4
## Capabilities
5
6
### Framework Trait
7
8
Main interface that test frameworks must implement to integrate with the SBT testing infrastructure.
9
10
```scala { .api }
11
/**
12
* Interface implemented by test frameworks.
13
* Must be annotated with @EnableReflectiveInstantiation for Scala.js compatibility.
14
*/
15
trait Framework {
16
/** A human-friendly name of the test framework that this object represents. */
17
def name(): String
18
19
/** An array of Fingerprints that specify how to identify test classes during discovery. */
20
def fingerprints(): Array[Fingerprint]
21
22
/**
23
* Initiates a run.
24
* @param args the test-framework-specific arguments for the new run
25
* @param remoteArgs the test-framework-specific remote arguments for the run in a forked JVM
26
* @param testClassLoader a class loader to use when loading test classes during the run
27
* @return a Runner representing the newly started run
28
* @throws IllegalStateException if unable to initiate run due to concurrent execution
29
*/
30
def runner(args: Array[String], remoteArgs: Array[String],
31
testClassLoader: ClassLoader): Runner
32
33
/**
34
* Scala.js specific: Creates a worker runner for a given run.
35
* The worker may send a message to the controller runner by calling `send`.
36
* Note: This method is called `slaveRunner` rather than `workerRunner` for historical reasons.
37
* @param args the test-framework-specific arguments
38
* @param remoteArgs the test-framework-specific remote arguments
39
* @param testClassLoader class loader for test classes
40
* @param send function to send messages to the controller runner
41
* @return a Runner for worker execution
42
*/
43
def slaveRunner(args: Array[String], remoteArgs: Array[String],
44
testClassLoader: ClassLoader, send: String => Unit): Runner
45
}
46
```
47
48
**Usage Examples:**
49
50
```scala
51
import sbt.testing._
52
import scala.scalajs.reflect.annotation.EnableReflectiveInstantiation
53
54
@EnableReflectiveInstantiation
55
class MyTestFramework extends Framework {
56
def name(): String = "MyFramework"
57
58
def fingerprints(): Array[Fingerprint] = Array(
59
// Discover classes extending MyTestSuite
60
new SubclassFingerprint {
61
def isModule() = false
62
def superclassName() = "com.example.MyTestSuite"
63
def requireNoArgConstructor() = true
64
},
65
// Discover objects with @Test annotation
66
new AnnotatedFingerprint {
67
def isModule() = true
68
def annotationName() = "com.example.Test"
69
}
70
)
71
72
def runner(args: Array[String], remoteArgs: Array[String],
73
testClassLoader: ClassLoader): Runner = {
74
new MyTestRunner(args, remoteArgs, testClassLoader, isWorker = false)
75
}
76
77
def slaveRunner(args: Array[String], remoteArgs: Array[String],
78
testClassLoader: ClassLoader, send: String => Unit): Runner = {
79
new MyWorkerRunner(args, remoteArgs, testClassLoader, send)
80
}
81
}
82
83
// Controller runner implementation
84
class MyTestRunner(
85
val args: Array[String],
86
remoteArgs: Array[String],
87
testClassLoader: ClassLoader,
88
isWorker: Boolean
89
) extends Runner {
90
// ... implementation
91
}
92
93
// Worker runner with message passing
94
class MyWorkerRunner(
95
val args: Array[String],
96
remoteArgs: Array[String],
97
testClassLoader: ClassLoader,
98
send: String => Unit
99
) extends Runner {
100
101
def receiveMessage(msg: String): Option[String] = {
102
msg match {
103
case "status" => Some("worker-ready")
104
case "shutdown" =>
105
cleanup()
106
None
107
case _ => None
108
}
109
}
110
111
// ... other implementations
112
}
113
```
114
115
### Reflective Instantiation
116
117
Scala.js-specific annotation required for framework discovery and instantiation.
118
119
```scala { .api }
120
/**
121
* Annotation from scala.scalajs.reflect.annotation package
122
* Must be applied to Framework implementations for Scala.js compatibility
123
*/
124
@EnableReflectiveInstantiation
125
```
126
127
**Usage:**
128
129
```scala
130
import scala.scalajs.reflect.annotation.EnableReflectiveInstantiation
131
132
@EnableReflectiveInstantiation
133
class MyFramework extends Framework {
134
// Implementation
135
}
136
```
137
138
## Error Handling
139
140
### IllegalStateException
141
142
Thrown by `runner()` method when framework cannot initiate concurrent runs:
143
144
```scala
145
def runner(args: Array[String], remoteArgs: Array[String],
146
testClassLoader: ClassLoader): Runner = {
147
if (isRunning) {
148
throw new IllegalStateException(
149
"Cannot initiate new run while previous run is active"
150
)
151
}
152
// ... create runner
153
}
154
```
155
156
## Framework Lifecycle
157
158
1. **Discovery**: SBT discovers framework classes through service loading
159
2. **Instantiation**: Framework instance created using reflective instantiation
160
3. **Fingerprint Registration**: `fingerprints()` called to get test discovery patterns
161
4. **Runner Creation**: `runner()` or `slaveRunner()` called to create test runners
162
5. **Test Execution**: Runners execute tests and report results
163
6. **Cleanup**: Framework resources cleaned up after test completion