or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

discovery.mdevents.mdexecution.mdframework.mdindex.mdlogging.md

framework.mddocs/

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