scala - Ejecución paralela de pruebas.
sbt specs2 (5)
Además de lo escrito sobre sbt anterior, debe saber que specs2 ejecuta todos los ejemplos de sus especificaciones de forma concurrente de forma predeterminada.
Aún puede declarar que, para una especificación dada, los ejemplos deben ejecutarse secuencialmente. Para hacer eso, simplemente agregue una sequential
al comienzo de su especificación:
class WriteAndReadSpec extends Specification{
val file = new File("testFiles/tmp.txt")
sequential
"WriteAndRead" should {
...
}
}
Me he dado cuenta de que SBT está ejecutando mis pruebas specs2 en paralelo. Esto parece bueno, excepto que una de mis pruebas implica leer y escribir desde un archivo y, por lo tanto, falla de forma impredecible, por ejemplo, ver más abajo.
¿Hay mejores opciones que
- configurando todas las pruebas para ejecutarse en serie,
- ¿Usando nombres de archivos y desglosados por separado para cada prueba?
class WriteAndReadSpec extends Specification{
val file = new File("testFiles/tmp.txt")
"WriteAndRead" should {
"work once" in {
new FileWriter(file, false).append("Foo").close
Source.fromFile(file).getLines().toList(0) must_== "Foo"
}
"work twice" in {
new FileWriter(file, false).append("Bar").close
Source.fromFile(file).getLines().toList(0) must_== "Bar"
}
}
trait TearDown extends After {
def after = if(file.exists) file.delete
}
}
El enlace wiki que dio en su respuesta es bastante bueno, aunque hay un pequeño error en el ejemplo que podría desechar uno (aunque, al ser un wiki, puedo corregirlo). Aquí hay un project/Build.scala
que en realidad compila y produce los filtros esperados, aunque en realidad no lo probé con pruebas.
import sbt._
import Keys._
object B extends Build
{
lazy val root =
Project("root", file("."))
.configs( Serial )
.settings( inConfig(Serial)(Defaults.testTasks) : _*)
.settings(
libraryDependencies ++= specs,
testOptions in Test := Seq(Tests.Filter(parFilter)),
testOptions in Serial := Seq(Tests.Filter(serialFilter))
)
.settings( parallelExecution in Serial := false : _*)
def parFilter(name: String): Boolean = !(name startsWith "WriteAndReadSpec")
def serialFilter(name: String): Boolean = (name startsWith "WriteAndReadSpec")
lazy val Serial = config("serial") extend(Test)
lazy val specs = Seq(
"org.specs2" %% "specs2" % "1.6.1",
"org.specs2" %% "specs2-scalaz-core" % "6.0.1" % "test"
)
}
La secuencia fija de pruebas para las suites puede llevar a la interdependencia de los casos de prueba y la carga en el mantenimiento.
Preferiría probar sin tocar el sistema de archivos (sin importar si es una lógica de negocios o un código de serialización), o si es inevitable (en cuanto a la integración de pruebas con las fuentes de archivos), utilizaría la creación de archivos temporales:
// Create temp file.
File temp = File.createTempFile("pattern", ".suffix");
// Delete temp file when program exits.
temp.deleteOnExit();
Otras respuestas explicaron cómo usarlos para que se ejecuten secuencialmente.
Si bien son respuestas válidas, en mi opinión, es mejor cambiar las pruebas para que se ejecuten en paralelo. (si es posible)
En su ejemplo, use archivos diferentes para cada prueba. Si tiene DB involucrado: use usuarios diferentes (o aleatorios) (o cualquier otro aislamiento que pueda), etc.
Parece que hay una tercera opción, que es agrupar las pruebas en serie en una configuración y ejecutarlas por separado mientras ejecuta el resto en paralelo.
Compruebe este wiki , busque "Aplicación para ejecución paralela" .