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.
JUnit-compatible specification class that can be run by JUnit runners.
@RunWith(classOf[JUnitRunner])
abstract class SpecificationWithJUnit extends SpecificationUsage Example:
import org.specs2._
import org.specs2.runner.JUnitRunner
import org.junit.runner.RunWith
@RunWith(classOf[JUnitRunner])
class CalculatorJUnitSpec extends SpecificationWithJUnit { def is = s2"""
Calculator specification for JUnit
add two numbers $add
subtract numbers $subtract
"""
def add = Calculator.add(2, 3) must beEqualTo(5)
def subtract = Calculator.subtract(5, 2) must beEqualTo(3)
}Lightweight JUnit-compatible specification.
@RunWith(classOf[JUnitRunner])
abstract class SpecWithJUnit extends SpecUsage Example:
@RunWith(classOf[JUnitRunner])
class SimpleJUnitSpec extends SpecWithJUnit { def is = s2"""
Simple JUnit specification
basic test ${ 1 + 1 must beEqualTo(2) }
"""
}JUnit test runner implementation for executing specs2 specifications.
class JUnitRunner(klass: Class[_]) extends Runner {
def run(notifier: RunNotifier): Unit
def getDescription: Description
def testCount(): Int
}IDE Integration:
@RunWith(classOf[JUnitRunner]) specificationsMaven Integration:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
<configuration>
<includes>
<include>**/*Spec.java</include>
<include>**/*Test.java</include>
</includes>
</configuration>
</plugin>Integration trait for property-based testing with ScalaCheck.
trait ScalaCheckProperty {
def prop[T: Arbitrary](f: T => Boolean): Prop
def prop[T1: Arbitrary, T2: Arbitrary](f: (T1, T2) => Boolean): Prop
def prop[T1: Arbitrary, T2: Arbitrary, T3: Arbitrary](f: (T1, T2, T3) => Boolean): Prop
def forAll[T: Arbitrary](f: T => Boolean): Prop
def forAll[T: Arbitrary](gen: Gen[T])(f: T => Boolean): Prop
}Usage Example:
import org.specs2._
import org.specs2.scalacheck.ScalaCheckProperty
import org.scalacheck.{Arbitrary, Gen}
class PropertySpec extends Specification with ScalaCheckProperty { def is = s2"""
String properties
concatenation is associative $concatenationAssoc
reverse twice is identity $reverseTwice
length is preserved $lengthPreserved
"""
def concatenationAssoc = prop { (s1: String, s2: String, s3: String) =>
(s1 + s2) + s3 must beEqualTo(s1 + (s2 + s3))
}
def reverseTwice = prop { (s: String) =>
s.reverse.reverse must beEqualTo(s)
}
def lengthPreserved = prop { (s: String) =>
s.reverse.length must beEqualTo(s.length)
}
}Configuration parameters for ScalaCheck property testing.
case class ScalaCheckParameters(
minTestsOk: Int = 100,
maxDiscardRatio: Float = 5.0f,
minSize: Int = 0,
maxSize: Int = 100,
rng: java.util.Random = new java.util.Random,
workers: Int = 1,
testCallback: TestCallback = new TestCallback {},
maxDiscarded: Int = 500,
customClassLoader: Option[ClassLoader] = None
)Custom Parameters:
class CustomPropertySpec extends Specification with ScalaCheckProperty { def is = s2"""
Custom property testing
large dataset property $largeDataset
"""
implicit val params = ScalaCheckParameters(
minTestsOk = 1000, // Run 1000 tests instead of default 100
maxSize = 10000, // Generate larger test data
workers = 4 // Use 4 parallel workers
)
def largeDataset = prop { (list: List[Int]) =>
list.sorted.reverse must beEqualTo(list.sortWith(_ > _))
}
}Methods for creating properties from functions.
trait ScalaCheckPropertyCreation {
def property[T: Arbitrary](f: T => Prop): Property
def property[T: Arbitrary](name: String)(f: T => Prop): Property
def propertyWithSeed[T: Arbitrary](seed: Long)(f: T => Prop): Property
}DSL for convenient property definition.
trait ScalaCheckPropertyDsl {
def check[T: Arbitrary](f: T => Boolean): Fragment
def checkAll[T: Arbitrary](f: T => Boolean): Fragment
def verify[T: Arbitrary](f: T => Prop): Fragment
}DSL Usage:
class PropertyDslSpec extends Specification with ScalaCheckPropertyDsl { def is = s2"""
Property DSL examples
list concatenation ${check { (l1: List[Int], l2: List[Int]) =>
(l1 ++ l2).length == l1.length + l2.length
}}
string operations ${verify { (s: String) =>
(s.length >= 0) :| "length non-negative" &&
(s.reverse.reverse == s) :| "reverse is involution"
}}
"""
}Converting ScalaCheck properties to specs2 results.
trait AsResultProp {
implicit def propAsResult(prop: Prop): AsResult[Prop]
implicit def propertyAsResult(property: Property): AsResult[Property]
implicit def genAsResult[T](gen: Gen[T]): AsResult[Gen[T]]
}Fine-grained control over property testing:
case class Parameters(
minTestsOk: Int,
maxDiscardRatio: Float,
minSize: Int,
maxSize: Int,
rng: scala.util.Random,
workers: Int
)Configuration Example:
class ConfiguredPropertySpec extends Specification with ScalaCheckProperty {
// Override default parameters
override implicit val defaultParameters = Parameters(
minTestsOk = 500,
maxDiscardRatio = 10.0f,
minSize = 10,
maxSize = 1000,
workers = Runtime.getRuntime.availableProcessors
)
def is = s2"""
Configured property tests
expensive property $expensiveProperty
"""
def expensiveProperty = prop { (data: ComplexData) =>
expensiveValidation(data) must beTrue
}
}Enhanced failure reporting for property tests.
trait PrettyDetails {
def prettyFreqMap(freqMap: Map[Set[Any], Int]): String
def prettyTestRes(testRes: Test.Result): String
def prettyArgs(args: List[Arg[Any]]): String
}Integration with Mockito mocking framework.
trait Mockito {
def mock[T: ClassTag]: T
def mock[T: ClassTag](name: String): T
def mock[T: ClassTag](defaultAnswer: Answer[_]): T
def spy[T](realObject: T): T
// Verification methods
def verify[T](mock: T): T
def verify[T](mock: T, mode: VerificationMode): T
def verifyNoMoreInteractions(mocks: AnyRef*): Unit
def verifyZeroInteractions(mocks: AnyRef*): Unit
// Stubbing methods
def when[T](methodCall: T): OngoingStubbing[T]
def doReturn(value: Any): Stubber
def doThrow(throwable: Throwable): Stubber
def doAnswer(answer: Answer[_]): Stubber
def doNothing(): Stubber
}Usage Example:
import org.specs2._
import org.specs2.mock.Mockito
class MockitoSpec extends Specification with Mockito { def is = s2"""
Service with mocked dependencies
should call repository save method $callsSave
should handle repository exceptions $handlesException
"""
def callsSave = {
val mockRepo = mock[UserRepository]
val service = new UserService(mockRepo)
val user = User("john", "john@test.com")
when(mockRepo.save(user)).thenReturn(user.copy(id = Some(1)))
val result = service.createUser(user)
result.id must beSome(1)
verify(mockRepo).save(user)
}
def handlesException = {
val mockRepo = mock[UserRepository]
val service = new UserService(mockRepo)
val user = User("john", "john@test.com")
when(mockRepo.save(user)).thenThrow(new DatabaseException("Connection failed"))
service.createUser(user) must throwA[ServiceException]
}
}Argument Matchers:
import org.mockito.ArgumentMatchers._
def usesArgumentMatchers = {
val mockService = mock[EmailService]
when(mockService.send(any[String], contains("@test.com"), anyInt()))
.thenReturn(true)
mockService.send("subject", "user@test.com", 1) must beTrue
verify(mockService).send(eq("subject"), argThat(_.contains("@test.com")), gt(0))
}Capturing Arguments:
import org.mockito.{ArgumentCaptor, Mockito}
def capturesArguments = {
val mockRepo = mock[AuditRepository]
val service = new UserService(mockRepo)
val captor = ArgumentCaptor.forClass(classOf[AuditEvent])
service.deleteUser(123)
verify(mockRepo).save(captor.capture())
val event = captor.getValue
event.action must beEqualTo("DELETE")
event.entityId must beEqualTo(123)
}Integration with Hamcrest matchers for enhanced assertions.
trait HamcrestMatcherAdapter {
def adapt[T](hamcrestMatcher: org.hamcrest.Matcher[T]): Matcher[T]
implicit def hamcrestToSpecs2[T](hamcrestMatcher: org.hamcrest.Matcher[T]): Matcher[T]
}Usage Example:
import org.specs2._
import org.specs2.mock.HamcrestMatcherAdapter
import org.hamcrest.Matchers._
class HamcrestSpec extends Specification with HamcrestMatcherAdapter { def is = s2"""
Using Hamcrest matchers
string contains check $stringContains
collection size check $collectionSize
"""
def stringContains = {
"hello world" must adapt(containsString("world"))
}
def collectionSize = {
List(1, 2, 3) must adapt(hasSize(3))
}
}Code analysis using Scala compiler for dependency checking.
class CompilerDependencyFinder {
def findDependencies(classNames: List[String]): List[Dependency]
def findPackageDependencies(packageName: String): List[PackageDependency]
def checkCircularDependencies(packages: List[String]): List[CircularDependency]
}General interface for dependency analysis.
trait DependencyFinder {
def getPackageDependencies(packageNames: List[String]): Operation[List[PackageDependency]]
def getClassDependencies(className: String): Operation[List[ClassDependency]]
}Integration with Classycle for advanced dependency analysis.
class ClassycleDependencyFinder extends DependencyFinder {
def checkArchitectureRules(rules: List[ArchitectureRule]): List[RuleViolation]
def analyzeLayerDependencies(layers: List[Layer]): ArchitectureAnalysis
}Usage Example:
import org.specs2._
import org.specs2.analysis._
class ArchitectureSpec extends Specification { def is = s2"""
Architecture rules
layers should respect dependencies $layerDependencies
no circular dependencies $noCircularDeps
"""
def layerDependencies = {
val finder = new ClassycleDependencyFinder
val rules = List(
ArchitectureRule("service layer", "com.example.service",
canDependOn = List("com.example.domain", "com.example.repository"),
cannotDependOn = List("com.example.web")),
ArchitectureRule("web layer", "com.example.web",
canDependOn = List("com.example.service", "com.example.domain"),
cannotDependOn = List("com.example.repository"))
)
val violations = finder.checkArchitectureRules(rules)
violations must beEmpty
}
def noCircularDeps = {
val finder = new CompilerDependencyFinder
val packages = List("com.example.service", "com.example.repository", "com.example.domain")
val circular = finder.checkCircularDependencies(packages)
circular must beEmpty
}
}Integration for Google Web Toolkit projects.
trait GwtSpecification {
def gwtSetup(): Unit
def gwtTeardown(): Unit
def runInGwtMode[T](test: => T): T
}Note: GWT integration is provided for legacy support and may be deprecated in newer versions.
Integration with SBT's test framework interface.
class Specs2Framework extends TestFramework {
def name: String = "specs2"
def fingerprints: Array[Fingerprint] = Array(
SubclassFingerprint("org.specs2.Specification", false, true),
SubclassFingerprint("org.specs2.mutable.Specification", false, true),
SubclassFingerprint("org.specs2.Spec", false, true),
SubclassFingerprint("org.specs2.mutable.Spec", false, true)
)
}Creating custom test framework integrations:
class CustomRunner extends Runner2 {
def run(eventHandler: EventHandler, loggers: Array[Logger],
continuation: Array[Task] => Unit, args: Array[String]): Unit = {
// Custom runner implementation
}
def tasks(taskDefs: Array[TaskDef]): Array[Task] = {
// Convert task definitions to executable tasks
}
}@RunWith(classOf[JUnitRunner]) for IDE compatibility:| "label") for better failure diagnostics