Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

How Scala promotes TDD


Published on

This talk demonstrates why Scala is in my opinion the best language to do TDD on

Published in: Technology
  • Be the first to comment

How Scala promotes TDD

  1. 1. How Scalapromotes TDDaudience.filter(_.usesJava).foreach { member => sayHi(member)} How Scala allows you to write better and more testable code
  2. 2. À La CarteApéritif TDD and programing languagesEntrée A short overview of Scala’s featuresPlat Principal • Better value objects using Case Classes • Determinism via immutability
  3. 3. À La CartePlat Principal (cont’d) • Better type safety, no nulls and less exception throwing • Better composition and cross-cutting concerns using Traits • Declarative asynchronyLe Dessert • Specs2 • ScalaTest • Plain old JUnit • Mocking
  4. 4. Apéritif
  5. 5. TDD and programing languagesThere’s a set of programming language features that arenecessary in order to grow software using TDD. Theseinclude referential transparency, well-defined types thatare easy to declare, the ability to separate concerns intoindividual codes of block and, of course, providing themeans to write short, concise and clear tests.
  6. 6. Entrée
  7. 7. A short overview of Scala’s features• A functional/OO programming language that runs on the JVM• Everything is an object – no primitive types• Functions are first-class members, every function is a value, including what is usually an operator• Scala is statically-typed and supports type inference
  8. 8. A short overview of Scala’s features• Lambda expressions, closures and currying naturally• Pattern matching• Multiple inheritance through Traits• Scala is extensible, allowing you to write your own “language structures”
  9. 9. Plat Principal
  10. 10. Case ClassesGood software engineering makes use of value objects.These need to encapsulate the way they represent theirstate, to provide information hiding and to be easy class Cat(name: String, age: Int, kittens: Seq[Cat] = Nil)val philip = Cat(name = “Philip”, age = 9)val aKitten = Cat(age = 1, name = “Shraga”)val withKittens = philip.copy(kittens = Seq(aKitten))
  11. 11. Determinism via ImmutabilityScala encourages everything to be immutable by default:• Variables (vals)• Collections• Value objects (using Case Classes)• Composition of collaborators
  12. 12. Determinism via ImmutabilityAs a result, we get rid of annoying problems such asaliasing, concurrent modifications of collections andobjects that have an unknown statecase class Cat(kittens: Seq[Cat] = Nil, dirty: Boolean = true) extends Petclass Clinic(val shower: PetShower) { def wash(cat: Cat): Cat = { val kittens = shower.wash shower.wash(cat.copy(kittens = kittens) }}
  13. 13. Determinism via ImmutabilityTesting Clinic.wash() should prove quite simpleval shower = mock[PetShower]val clinic = new Clinic(shower)val kitten1 = Cat(dirty = true)val kitten2 = Cat(dirty = true)val mom = Cat(kittens = Seq(kitten1, kitten2)clinic.wash(mom)verify(shower).wash(kitten1)verify(shower).wash(kitten2)verify(shower).wash(mom)
  14. 14. Better type safety• Scala is statically and strongly typed; type inference keeps the code lean and mean• Stricter generics (in comparison to Java) provide better compile-time checks• Advanced features include structural types and type aliases
  15. 15. No nullsScala urges us to declare a possible return value using theOption[T] monad; an option can be either Some(value) orNone, and allows us to assume to it can never be null. Wecan use collection semantics to consume an Option[T].def foo: Option[Foo]foo match { case Some(Foo(bar)) => println(bar) case _ => println(“No foo found”)}val barOrDefault =“no foo”)
  16. 16. Less exception throwing using Try[T]• Try[T] is an abstract monad type with two concrete implementations, Success[T] and Failure[E]• Represents the result of an operation which may fail• Automatically translate an exception-throwing clause to a Try[T] using the Try() apply method
  17. 17. Less exception throwingclass SomeJavaObject { public Bar tryFoo() throws FooException {…}}val someJavaObject = new SomeJavaObjectval maybeBar = Try(someJavaObject.tryFoo())maybeBar match { case Success(bar) => println(bar) case _ => reportFailureAndRetry()}
  18. 18. Better composition using TraitsScala provides the means for multiple inheritance usingTraits; this can be useful for separating related butindependent pieces of logic into separate units of code,each with its own test suite.class ComponentFactory extends ImageCreation with TextCreation with VideoCreation with … { def create(cd: ComponentDefinition) = cd match { case Image(url, dimensions) => makeImage(…) case Text(text, kind) => makeText(…) … }}
  19. 19. Better composition using Traitstrait ImageCreation { def makeImage(url: String, dimensions: Dimensions) = {…}}class ImageCreationTest extends SpecificationWithJUnit { val creator = new ImageCreation {… // init code} “makeImage” should { “create an image” in {…} “fail gracefully” in {…} }}
  20. 20. Cross-cutting concerns using TraitsIn the Java world, AOP can be used to add cross-cuttingconcerns to existing code without altering it, but has thedownside of being non-transparent or too implicit. Thismakes it hard to figure out which aspects are applied atruntime, and impossible to test that aspects are indeedbeing applied properly.Let’s look at an example using the canonical use case forAOP – auditing.
  21. 21. Cross-cutting concerns using Traitstrait Auditing { def auditor: Auditor def audited(f: () => T): T = { auditor.before(…) val ret: T = f() auditor.after(…) ret }}class Foo(baz: Baz, val auditor: Auditor) extends Auditing { def bar() { audited { baz.doSomething() } }}
  22. 22. Cross-cutting concerns using Traitsclass FooTest extends SpecificationWithJUnit { val auditor = mock[Auditor] val baz = mock[Baz] val foo = new Foo(baz, auditor) “Foo” should { “call baz” in { got { one(baz).doSomething() one(auditor).audit(…) } } }}
  23. 23. Declarative asynchronyScala 2.10 adds a top notch Promise/Future library withsupport for composing and pipelining, using callback ormonadic semantics.A Future[T] will never throw an exception, it will return aTry[T].
  24. 24. Declarative asynchronytrait CatVaccinator{ def vaccinate(cat: Cat): Future[VaccinatedCat]}trait PetStore { def deliver(cats: Seq[VaccinatedCat]): Unit}class Vet(vaccinator: CatVaccinator, petStore: PetStore){ def deliver(cats: Seq[Cat]) { Future.sequence( vaccinator.vaccinate) .onSuccess { vaccinatedCats: Seq[VaccinatedCat] => petStore.deliver(vaccinatedCats) } .onFailure { exception => reportAndRetry(cats) // some retry logic } }}
  25. 25. Declarative asynchrony// SameThreadExecutor or DeterministicExecutorval executorService: ExecutorService = …val vaccinator = mock[CatVaccinator]val petStore = mock[PetStore]val vet = new Vet(vaccinator, petStore)“Vet” should { “call deliver” in { vaccinator.vaccinate(cat1) returns Future(vcat1) vaccinator.vaccinate(cat2) returns Future(vcat2) vet.deliver(Seq(cat1, cat2)) got { one(petStore).deliver(Seq(vcat1, vcat2)) } }}
  26. 26. Le Dessert
  27. 27. Specs2• Is somewhat of a de-facto standard in the Scala community• Github, active community, frequent releases• Support for RSpec-style and BDD-style test code• Rich matcher library• Mediocre documentation• Built-in Hamcrest integration
  28. 28. ScalaTest• Somewhat behind Specs2 in terms of adoption• Supports a myriad of test formats (RSpec, BDD, XUnit, etc)• Rich and reliable documentation• Poor matcher library• No built-in Hamcrest integration
  29. 29. Plain-old JUnit• Lots of boilerplate• Hamcrest doesn’t play well with Scala (for instance, for matching collections)• Less magic in comparison with Specs2 and ScalaTest• No namespace collisions and easier to debug if something weird happens
  30. 30. Mocking• ScalaTest supports ScalaMock, Mockito, JMock and EasyMock• Specs2 only supports Mockito out of the box but writing your own sugar using Mixin traits is easy• ScalaMock is a native Scala mock objects library. Worth adopting if you don’t already rely heavily on another library
  31. 31. Questions? shaiy@wix.com