0
# Integration Features
1
2
Specs2 provides comprehensive integration modules for popular testing frameworks and tools including JUnit, ScalaCheck for property-based testing, Mockito for mocking, and analysis tools for code dependencies.
3
4
## JUnit Integration
5
6
### SpecificationWithJUnit
7
8
JUnit-compatible specification class that can be run by JUnit runners.
9
10
```scala { .api }
11
@RunWith(classOf[JUnitRunner])
12
abstract class SpecificationWithJUnit extends Specification
13
```
14
15
**Usage Example:**
16
```scala
17
import org.specs2._
18
import org.specs2.runner.JUnitRunner
19
import org.junit.runner.RunWith
20
21
@RunWith(classOf[JUnitRunner])
22
class CalculatorJUnitSpec extends SpecificationWithJUnit { def is = s2"""
23
Calculator specification for JUnit
24
add two numbers $add
25
subtract numbers $subtract
26
"""
27
28
def add = Calculator.add(2, 3) must beEqualTo(5)
29
def subtract = Calculator.subtract(5, 2) must beEqualTo(3)
30
}
31
```
32
33
### SpecWithJUnit
34
35
Lightweight JUnit-compatible specification.
36
37
```scala { .api }
38
@RunWith(classOf[JUnitRunner])
39
abstract class SpecWithJUnit extends Spec
40
```
41
42
**Usage Example:**
43
```scala
44
@RunWith(classOf[JUnitRunner])
45
class SimpleJUnitSpec extends SpecWithJUnit { def is = s2"""
46
Simple JUnit specification
47
basic test ${ 1 + 1 must beEqualTo(2) }
48
"""
49
}
50
```
51
52
### JUnitRunner
53
54
JUnit test runner implementation for executing specs2 specifications.
55
56
```scala { .api }
57
class JUnitRunner(klass: Class[_]) extends Runner {
58
def run(notifier: RunNotifier): Unit
59
def getDescription: Description
60
def testCount(): Int
61
}
62
```
63
64
**IDE Integration:**
65
- IntelliJ IDEA: Automatically recognizes `@RunWith(classOf[JUnitRunner])` specifications
66
- Eclipse: Supports JUnit runner integration
67
- NetBeans: Compatible with JUnit test execution
68
69
**Maven Integration:**
70
```xml
71
<plugin>
72
<groupId>org.apache.maven.plugins</groupId>
73
<artifactId>maven-surefire-plugin</artifactId>
74
<version>2.22.2</version>
75
<configuration>
76
<includes>
77
<include>**/*Spec.java</include>
78
<include>**/*Test.java</include>
79
</includes>
80
</configuration>
81
</plugin>
82
```
83
84
## ScalaCheck Integration
85
86
### ScalaCheckProperty
87
88
Integration trait for property-based testing with ScalaCheck.
89
90
```scala { .api }
91
trait ScalaCheckProperty {
92
def prop[T: Arbitrary](f: T => Boolean): Prop
93
def prop[T1: Arbitrary, T2: Arbitrary](f: (T1, T2) => Boolean): Prop
94
def prop[T1: Arbitrary, T2: Arbitrary, T3: Arbitrary](f: (T1, T2, T3) => Boolean): Prop
95
def forAll[T: Arbitrary](f: T => Boolean): Prop
96
def forAll[T: Arbitrary](gen: Gen[T])(f: T => Boolean): Prop
97
}
98
```
99
100
**Usage Example:**
101
```scala
102
import org.specs2._
103
import org.specs2.scalacheck.ScalaCheckProperty
104
import org.scalacheck.{Arbitrary, Gen}
105
106
class PropertySpec extends Specification with ScalaCheckProperty { def is = s2"""
107
String properties
108
concatenation is associative $concatenationAssoc
109
reverse twice is identity $reverseTwice
110
length is preserved $lengthPreserved
111
"""
112
113
def concatenationAssoc = prop { (s1: String, s2: String, s3: String) =>
114
(s1 + s2) + s3 must beEqualTo(s1 + (s2 + s3))
115
}
116
117
def reverseTwice = prop { (s: String) =>
118
s.reverse.reverse must beEqualTo(s)
119
}
120
121
def lengthPreserved = prop { (s: String) =>
122
s.reverse.length must beEqualTo(s.length)
123
}
124
}
125
```
126
127
### ScalaCheckParameters
128
129
Configuration parameters for ScalaCheck property testing.
130
131
```scala { .api }
132
case class ScalaCheckParameters(
133
minTestsOk: Int = 100,
134
maxDiscardRatio: Float = 5.0f,
135
minSize: Int = 0,
136
maxSize: Int = 100,
137
rng: java.util.Random = new java.util.Random,
138
workers: Int = 1,
139
testCallback: TestCallback = new TestCallback {},
140
maxDiscarded: Int = 500,
141
customClassLoader: Option[ClassLoader] = None
142
)
143
```
144
145
**Custom Parameters:**
146
```scala
147
class CustomPropertySpec extends Specification with ScalaCheckProperty { def is = s2"""
148
Custom property testing
149
large dataset property $largeDataset
150
"""
151
152
implicit val params = ScalaCheckParameters(
153
minTestsOk = 1000, // Run 1000 tests instead of default 100
154
maxSize = 10000, // Generate larger test data
155
workers = 4 // Use 4 parallel workers
156
)
157
158
def largeDataset = prop { (list: List[Int]) =>
159
list.sorted.reverse must beEqualTo(list.sortWith(_ > _))
160
}
161
}
162
```
163
164
### ScalaCheckPropertyCreation
165
166
Methods for creating properties from functions.
167
168
```scala { .api }
169
trait ScalaCheckPropertyCreation {
170
def property[T: Arbitrary](f: T => Prop): Property
171
def property[T: Arbitrary](name: String)(f: T => Prop): Property
172
def propertyWithSeed[T: Arbitrary](seed: Long)(f: T => Prop): Property
173
}
174
```
175
176
### ScalaCheckPropertyDsl
177
178
DSL for convenient property definition.
179
180
```scala { .api }
181
trait ScalaCheckPropertyDsl {
182
def check[T: Arbitrary](f: T => Boolean): Fragment
183
def checkAll[T: Arbitrary](f: T => Boolean): Fragment
184
def verify[T: Arbitrary](f: T => Prop): Fragment
185
}
186
```
187
188
**DSL Usage:**
189
```scala
190
class PropertyDslSpec extends Specification with ScalaCheckPropertyDsl { def is = s2"""
191
Property DSL examples
192
list concatenation ${check { (l1: List[Int], l2: List[Int]) =>
193
(l1 ++ l2).length == l1.length + l2.length
194
}}
195
196
string operations ${verify { (s: String) =>
197
(s.length >= 0) :| "length non-negative" &&
198
(s.reverse.reverse == s) :| "reverse is involution"
199
}}
200
"""
201
}
202
```
203
204
### AsResultProp
205
206
Converting ScalaCheck properties to specs2 results.
207
208
```scala { .api }
209
trait AsResultProp {
210
implicit def propAsResult(prop: Prop): AsResult[Prop]
211
implicit def propertyAsResult(property: Property): AsResult[Property]
212
implicit def genAsResult[T](gen: Gen[T]): AsResult[Gen[T]]
213
}
214
```
215
216
### Parameters and Configuration
217
218
Fine-grained control over property testing:
219
220
```scala { .api }
221
case class Parameters(
222
minTestsOk: Int,
223
maxDiscardRatio: Float,
224
minSize: Int,
225
maxSize: Int,
226
rng: scala.util.Random,
227
workers: Int
228
)
229
```
230
231
**Configuration Example:**
232
```scala
233
class ConfiguredPropertySpec extends Specification with ScalaCheckProperty {
234
// Override default parameters
235
override implicit val defaultParameters = Parameters(
236
minTestsOk = 500,
237
maxDiscardRatio = 10.0f,
238
minSize = 10,
239
maxSize = 1000,
240
workers = Runtime.getRuntime.availableProcessors
241
)
242
243
def is = s2"""
244
Configured property tests
245
expensive property $expensiveProperty
246
"""
247
248
def expensiveProperty = prop { (data: ComplexData) =>
249
expensiveValidation(data) must beTrue
250
}
251
}
252
```
253
254
### PrettyDetails
255
256
Enhanced failure reporting for property tests.
257
258
```scala { .api }
259
trait PrettyDetails {
260
def prettyFreqMap(freqMap: Map[Set[Any], Int]): String
261
def prettyTestRes(testRes: Test.Result): String
262
def prettyArgs(args: List[Arg[Any]]): String
263
}
264
```
265
266
## Mockito Integration
267
268
### Mockito
269
270
Integration with Mockito mocking framework.
271
272
```scala { .api }
273
trait Mockito {
274
def mock[T: ClassTag]: T
275
def mock[T: ClassTag](name: String): T
276
def mock[T: ClassTag](defaultAnswer: Answer[_]): T
277
def spy[T](realObject: T): T
278
279
// Verification methods
280
def verify[T](mock: T): T
281
def verify[T](mock: T, mode: VerificationMode): T
282
def verifyNoMoreInteractions(mocks: AnyRef*): Unit
283
def verifyZeroInteractions(mocks: AnyRef*): Unit
284
285
// Stubbing methods
286
def when[T](methodCall: T): OngoingStubbing[T]
287
def doReturn(value: Any): Stubber
288
def doThrow(throwable: Throwable): Stubber
289
def doAnswer(answer: Answer[_]): Stubber
290
def doNothing(): Stubber
291
}
292
```
293
294
**Usage Example:**
295
```scala
296
import org.specs2._
297
import org.specs2.mock.Mockito
298
299
class MockitoSpec extends Specification with Mockito { def is = s2"""
300
Service with mocked dependencies
301
should call repository save method $callsSave
302
should handle repository exceptions $handlesException
303
"""
304
305
def callsSave = {
306
val mockRepo = mock[UserRepository]
307
val service = new UserService(mockRepo)
308
val user = User("john", "john@test.com")
309
310
when(mockRepo.save(user)).thenReturn(user.copy(id = Some(1)))
311
312
val result = service.createUser(user)
313
314
result.id must beSome(1)
315
verify(mockRepo).save(user)
316
}
317
318
def handlesException = {
319
val mockRepo = mock[UserRepository]
320
val service = new UserService(mockRepo)
321
val user = User("john", "john@test.com")
322
323
when(mockRepo.save(user)).thenThrow(new DatabaseException("Connection failed"))
324
325
service.createUser(user) must throwA[ServiceException]
326
}
327
}
328
```
329
330
### Advanced Mocking Features
331
332
**Argument Matchers:**
333
```scala
334
import org.mockito.ArgumentMatchers._
335
336
def usesArgumentMatchers = {
337
val mockService = mock[EmailService]
338
339
when(mockService.send(any[String], contains("@test.com"), anyInt()))
340
.thenReturn(true)
341
342
mockService.send("subject", "user@test.com", 1) must beTrue
343
verify(mockService).send(eq("subject"), argThat(_.contains("@test.com")), gt(0))
344
}
345
```
346
347
**Capturing Arguments:**
348
```scala
349
import org.mockito.{ArgumentCaptor, Mockito}
350
351
def capturesArguments = {
352
val mockRepo = mock[AuditRepository]
353
val service = new UserService(mockRepo)
354
val captor = ArgumentCaptor.forClass(classOf[AuditEvent])
355
356
service.deleteUser(123)
357
358
verify(mockRepo).save(captor.capture())
359
val event = captor.getValue
360
event.action must beEqualTo("DELETE")
361
event.entityId must beEqualTo(123)
362
}
363
```
364
365
### HamcrestMatcherAdapter
366
367
Integration with Hamcrest matchers for enhanced assertions.
368
369
```scala { .api }
370
trait HamcrestMatcherAdapter {
371
def adapt[T](hamcrestMatcher: org.hamcrest.Matcher[T]): Matcher[T]
372
implicit def hamcrestToSpecs2[T](hamcrestMatcher: org.hamcrest.Matcher[T]): Matcher[T]
373
}
374
```
375
376
**Usage Example:**
377
```scala
378
import org.specs2._
379
import org.specs2.mock.HamcrestMatcherAdapter
380
import org.hamcrest.Matchers._
381
382
class HamcrestSpec extends Specification with HamcrestMatcherAdapter { def is = s2"""
383
Using Hamcrest matchers
384
string contains check $stringContains
385
collection size check $collectionSize
386
"""
387
388
def stringContains = {
389
"hello world" must adapt(containsString("world"))
390
}
391
392
def collectionSize = {
393
List(1, 2, 3) must adapt(hasSize(3))
394
}
395
}
396
```
397
398
## Analysis Features
399
400
### CompilerDependencyFinder
401
402
Code analysis using Scala compiler for dependency checking.
403
404
```scala { .api }
405
class CompilerDependencyFinder {
406
def findDependencies(classNames: List[String]): List[Dependency]
407
def findPackageDependencies(packageName: String): List[PackageDependency]
408
def checkCircularDependencies(packages: List[String]): List[CircularDependency]
409
}
410
```
411
412
### DependencyFinder
413
414
General interface for dependency analysis.
415
416
```scala { .api }
417
trait DependencyFinder {
418
def getPackageDependencies(packageNames: List[String]): Operation[List[PackageDependency]]
419
def getClassDependencies(className: String): Operation[List[ClassDependency]]
420
}
421
```
422
423
### ClassycleDependencyFinder
424
425
Integration with Classycle for advanced dependency analysis.
426
427
```scala { .api }
428
class ClassycleDependencyFinder extends DependencyFinder {
429
def checkArchitectureRules(rules: List[ArchitectureRule]): List[RuleViolation]
430
def analyzeLayerDependencies(layers: List[Layer]): ArchitectureAnalysis
431
}
432
```
433
434
**Usage Example:**
435
```scala
436
import org.specs2._
437
import org.specs2.analysis._
438
439
class ArchitectureSpec extends Specification { def is = s2"""
440
Architecture rules
441
layers should respect dependencies $layerDependencies
442
no circular dependencies $noCircularDeps
443
"""
444
445
def layerDependencies = {
446
val finder = new ClassycleDependencyFinder
447
val rules = List(
448
ArchitectureRule("service layer", "com.example.service",
449
canDependOn = List("com.example.domain", "com.example.repository"),
450
cannotDependOn = List("com.example.web")),
451
ArchitectureRule("web layer", "com.example.web",
452
canDependOn = List("com.example.service", "com.example.domain"),
453
cannotDependOn = List("com.example.repository"))
454
)
455
456
val violations = finder.checkArchitectureRules(rules)
457
violations must beEmpty
458
}
459
460
def noCircularDeps = {
461
val finder = new CompilerDependencyFinder
462
val packages = List("com.example.service", "com.example.repository", "com.example.domain")
463
val circular = finder.checkCircularDependencies(packages)
464
circular must beEmpty
465
}
466
}
467
```
468
469
## GWT Integration
470
471
### GWT Support
472
473
Integration for Google Web Toolkit projects.
474
475
```scala { .api }
476
trait GwtSpecification {
477
def gwtSetup(): Unit
478
def gwtTeardown(): Unit
479
def runInGwtMode[T](test: => T): T
480
}
481
```
482
483
**Note**: GWT integration is provided for legacy support and may be deprecated in newer versions.
484
485
## Testing Framework Integration
486
487
### TestFramework Integration
488
489
Integration with SBT's test framework interface.
490
491
```scala { .api }
492
class Specs2Framework extends TestFramework {
493
def name: String = "specs2"
494
def fingerprints: Array[Fingerprint] = Array(
495
SubclassFingerprint("org.specs2.Specification", false, true),
496
SubclassFingerprint("org.specs2.mutable.Specification", false, true),
497
SubclassFingerprint("org.specs2.Spec", false, true),
498
SubclassFingerprint("org.specs2.mutable.Spec", false, true)
499
)
500
}
501
```
502
503
### Custom Test Interfaces
504
505
Creating custom test framework integrations:
506
507
```scala
508
class CustomRunner extends Runner2 {
509
def run(eventHandler: EventHandler, loggers: Array[Logger],
510
continuation: Array[Task] => Unit, args: Array[String]): Unit = {
511
// Custom runner implementation
512
}
513
514
def tasks(taskDefs: Array[TaskDef]): Array[Task] = {
515
// Convert task definitions to executable tasks
516
}
517
}
518
```
519
520
## Best Practices
521
522
### JUnit Integration
523
524
1. **Use `@RunWith(classOf[JUnitRunner])`** for IDE compatibility
525
2. **Combine with Maven/Gradle** for build tool integration
526
3. **Generate JUnit XML reports** for CI/CD integration
527
4. **Keep specification structure simple** for JUnit compatibility
528
529
### ScalaCheck Integration
530
531
1. **Start with simple properties** and build complexity gradually
532
2. **Use meaningful property names** for better failure reporting
533
3. **Configure appropriate test counts** based on property complexity
534
4. **Leverage custom generators** for domain-specific data
535
5. **Use labels** (`:| "label"`) for better failure diagnostics
536
537
### Mockito Integration
538
539
1. **Mock external dependencies** only, not domain objects
540
2. **Verify interactions** that are important to the business logic
541
3. **Use argument captors** for complex verification scenarios
542
4. **Reset mocks** between tests when necessary
543
5. **Prefer real objects** over mocks when possible
544
545
### Architecture Testing
546
547
1. **Define clear layer boundaries** and enforce them with analysis
548
2. **Check for circular dependencies** regularly
549
3. **Use architecture rules** to prevent regression
550
4. **Document architectural decisions** in test specifications
551
5. **Run architecture tests** as part of continuous integration
552
553
### General Integration
554
555
1. **Choose appropriate integrations** based on project needs
556
2. **Keep integration code simple** and focused
557
3. **Document integration requirements** and setup procedures
558
4. **Test integrations** in isolation when possible
559
5. **Monitor integration performance** and optimize as needed