Les proves són una part essencial del desenvolupament de programari, ja que asseguren que el codi funcioni com s'espera i ajuden a detectar errors abans que arribin a producció. En aquest tema, aprendrem com realitzar proves en Scala utilitzant diverses eines i biblioteques.

Continguts

Introducció a les Proves

Les proves de programari es poden classificar en diverses categories, incloent-hi:

  • Proves Unitàries: Verifiquen la funcionalitat de components individuals del codi, com ara funcions o mètodes.
  • Proves d'Integració: Asseguren que diferents components del sistema funcionin correctament junts.
  • Proves de Propietats: Verifiquen que el codi compleixi amb certes propietats o invariants.
  • Proves de Sistema: Verifiquen el sistema complet en un entorn que simula la producció.

Eines de Proves en Scala

Scala té diverses eines i biblioteques per a realitzar proves. Algunes de les més populars són:

  • ScalaTest: Una biblioteca de proves unitàries molt utilitzada en la comunitat Scala.
  • ScalaCheck: Una biblioteca per a proves de propietats basada en el concepte de generació aleatòria de dades de prova.
  • Specs2: Una altra biblioteca de proves que combina proves unitàries i de propietats.

Proves Unitàries amb ScalaTest

ScalaTest és una de les biblioteques de proves més populars per a Scala. Proporciona una API rica i flexible per a escriure proves unitàries.

Instal·lació de ScalaTest

Per començar a utilitzar ScalaTest, primer hem d'afegir la dependència al nostre fitxer build.sbt:

libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.10" % Test

Exemple de Prova Unitària

A continuació, es mostra un exemple de prova unitària utilitzant ScalaTest:

import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers

class CalculatorSpec extends AnyFlatSpec with Matchers {

  "A Calculator" should "add two numbers correctly" in {
    val calculator = new Calculator
    calculator.add(2, 3) shouldEqual 5
  }

  it should "subtract two numbers correctly" in {
    val calculator = new Calculator
    calculator.subtract(5, 3) shouldEqual 2
  }
}

class Calculator {
  def add(a: Int, b: Int): Int = a + b
  def subtract(a: Int, b: Int): Int = a - b
}

Explicació del Codi

  • Imports: Importem les classes necessàries de ScalaTest.
  • CalculatorSpec: Definim una classe de prova que extén AnyFlatSpec i Matchers.
  • Proves: Definim dues proves per a la classe Calculator utilitzant el mètode should per a les expectatives.

Proves de Propietats amb ScalaCheck

ScalaCheck és una biblioteca per a proves de propietats que genera dades de prova aleatòries per verificar que el codi compleixi amb certes propietats.

Instal·lació de ScalaCheck

Afegim la dependència al nostre fitxer build.sbt:

libraryDependencies += "org.scalacheck" %% "scalacheck" % "1.15.4" % Test

Exemple de Prova de Propietats

A continuació, es mostra un exemple de prova de propietats utilitzant ScalaCheck:

import org.scalacheck.Properties
import org.scalacheck.Prop.forAll

object CalculatorProperties extends Properties("Calculator") {

  property("addition commutativity") = forAll { (a: Int, b: Int) =>
    val calculator = new Calculator
    calculator.add(a, b) == calculator.add(b, a)
  }

  property("subtraction non-commutativity") = forAll { (a: Int, b: Int) =>
    val calculator = new Calculator
    calculator.subtract(a, b) != calculator.subtract(b, a)
  }
}

class Calculator {
  def add(a: Int, b: Int): Int = a + b
  def subtract(a: Int, b: Int): Int = a - b
}

Explicació del Codi

  • Imports: Importem les classes necessàries de ScalaCheck.
  • CalculatorProperties: Definim un objecte de propietats per a la classe Calculator.
  • Propietats: Definim dues propietats utilitzant el mètode forAll per a la generació de dades aleatòries.

Proves d'Integració

Les proves d'integració asseguren que diferents components del sistema funcionin correctament junts. En Scala, podem utilitzar ScalaTest o altres eines per a realitzar proves d'integració.

Exemple de Prova d'Integració

A continuació, es mostra un exemple de prova d'integració utilitzant ScalaTest:

import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers

class IntegrationSpec extends AnyFlatSpec with Matchers {

  "A System" should "work correctly with multiple components" in {
    val componentA = new ComponentA
    val componentB = new ComponentB
    val system = new System(componentA, componentB)

    system.performOperation() shouldEqual "Operation Successful"
  }
}

class ComponentA {
  def operationA(): String = "A"
}

class ComponentB {
  def operationB(): String = "B"
}

class System(componentA: ComponentA, componentB: ComponentB) {
  def performOperation(): String = {
    if (componentA.operationA() == "A" && componentB.operationB() == "B") {
      "Operation Successful"
    } else {
      "Operation Failed"
    }
  }
}

Explicació del Codi

  • Imports: Importem les classes necessàries de ScalaTest.
  • IntegrationSpec: Definim una classe de prova d'integració.
  • Prova d'Integració: Verifiquem que el sistema funcioni correctament amb múltiples components.

Exercicis Pràctics

  1. Prova Unitària: Escriu una prova unitària per a una funció que multiplica dos nombres.
  2. Prova de Propietats: Escriu una prova de propietats per a una funció que inverteix una cadena.
  3. Prova d'Integració: Escriu una prova d'integració per a un sistema que combina dues llistes en una sola.

Solucions

  1. Prova Unitària:
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers

class MultiplicationSpec extends AnyFlatSpec with Matchers {

  "A Multiplication" should "multiply two numbers correctly" in {
    val result = multiply(2, 3)
    result shouldEqual 6
  }

  def multiply(a: Int, b: Int): Int = a * b
}
  1. Prova de Propietats:
import org.scalacheck.Properties
import org.scalacheck.Prop.forAll

object StringProperties extends Properties("String") {

  property("reverse twice is identity") = forAll { (s: String) =>
    s.reverse.reverse == s
  }
}
  1. Prova d'Integració:
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers

class ListIntegrationSpec extends AnyFlatSpec with Matchers {

  "A ListCombiner" should "combine two lists correctly" in {
    val list1 = List(1, 2, 3)
    val list2 = List(4, 5, 6)
    val combinedList = combineLists(list1, list2)
    combinedList shouldEqual List(1, 2, 3, 4, 5, 6)
  }

  def combineLists(list1: List[Int], list2: List[Int]): List[Int] = list1 ++ list2
}

Conclusió

En aquest tema, hem après com realitzar proves en Scala utilitzant diverses eines i biblioteques. Hem cobert les proves unitàries amb ScalaTest, les proves de propietats amb ScalaCheck i les proves d'integració. Les proves són una part crucial del desenvolupament de programari i ajuden a assegurar que el codi funcioni correctament i sigui robust.

En el següent tema, explorarem el Play Framework, un marc de treball per a aplicacions web en Scala.

© Copyright 2024. Tots els drets reservats