Este módulo proporciona pruebas unitarias para otros módulos de Lua . Para probar un módulo, debe crear un módulo de prueba independiente, que normalmente se encuentra en . El módulo se prueba con el módulo ScribuntoUnit, que verifica que las operaciones definidas en el módulo de prueba produzcan los resultados esperados.Module:Module name/testcases
Para crear un módulo de prueba (suite de pruebas), comience con el siguiente código:
local myModule = require ( 'Module:MyModule' ) - el módulo que se va a probar local ScribuntoUnit = require ( 'Module:ScribuntoUnit' ) local suite = ScribuntoUnit : new ()
Una vez que hayas hecho esto, puedes agregar funciones de prueba individuales al suite
objeto. Cualquier función que comience con test
se trata como una prueba. (ScribuntoUnit ignorará otras funciones, pero se pueden usar en las pruebas mismas).
suite de funciones : testSomeCall () self : assertEquals ( 'valor esperado' , myModule.someCall ( 123 ) ) self : assertEquals ( ' otro valor esperado' , myModule.someCall ( 456 ) ) fin suite de funciones : testSomeOtherCall () self : assertEquals ( 'valor esperado' , myModule.someOtherCall ( 123 ) ) self : assertEquals ( ' otro valor esperado' , myModule.someOtherCall ( 456 ) ) fin
Las pruebas que escriba deben realizar afirmaciones y ScribuntoUnit comprobará si esas afirmaciones son verdaderas. Por ejemplo, assertEquals
comprueba que ambos argumentos que se le proporcionan sean iguales. Si ScribuntoUnit no encuentra que una afirmación sea verdadera, la prueba fallará y se generará un mensaje de error. El mensaje de error mostrará qué afirmación no superó la verificación (no se realizan otras comprobaciones de las afirmaciones en este momento).
Para finalizar el módulo de prueba, debe devolver el suite
objeto.
suite de regreso
Las pruebas se pueden ejecutar de dos maneras: a través de la consola de depuración de Lua y desde una página wiki usando #invoke. Si está ejecutando las pruebas a través de la consola de depuración, use el código require('Module:MyModule/testcases').run()
. Si las está ejecutando desde una página wiki, use el código {{#invoke:MyModule/testcases|run}}
. Esto generará una tabla que contiene los resultados. También es posible mostrar una tabla más compacta usando el código {{#invoke:MyModule/testcases|run|displayMode=short}}
.
El último parámetro de todos los métodos de prueba es un mensaje que se muestra si falla la validación.
self : assertEquals ( "valor esperado" , myModule . someCall ( 123 ), "La llamada a myModule.someCall(123) no devolvió el valor esperado." )
yo : error ( mensaje )
Falla una prueba incondicionalmente.
self : fail ( "La prueba falló debido a X." )
self : assertTrue ( expresión , mensaje ) self : assertFalse ( expresión , mensaje )
Estos comprueban si la expresión dada se evalúa como true
o false
. Tenga en cuenta que en Lua false
y nil
se evalúan como false
, y todo lo demás se evalúa como true
.
yo mismo : afirmarVerdadero ( 2 + 2 == 4 ) yo mismo : afirmarVerdadero ( 'foo' ) yo mismo : afirmarFalso ( 2 + 2 == 5 ) yo mismo : afirmarFalso ( nulo )
self : assertStringContains ( patrón , s , simple , mensaje )
Esto prueba si pattern
se encuentra en la cadena s
. Si plain
es verdadero, pattern
se interpreta como texto literal; de lo contrario, pattern
se interpreta como un patrón ustring.
Si no se encuentra la cadena, el mensaje de error muestra los valores de pattern
y s
; si s
tiene más de 70 caracteres, se muestra una versión truncada. Este método es útil para probar comportamientos específicos en wikitextos complejos.
self : assertStringContains ( "foo" , "foobar" ) -- pasa self : assertStringContains ( "foo" , "fobar" ) -- falla self : assertStringContains ( ".oo" , "foobar" ) -- pasa: coincide con "foo" self : assertStringContains ( ".oo" , "foobar" , true ) -- falla: . se interpreta como un carácter literal
self : assertNotStringContains ( patrón , s , simple , mensaje )
Esto es lo opuesto de assertStringContains
. La prueba fallará si pattern
se encuentra en la cadena s
. Si plain
es verdadero, pattern
se interpreta como texto literal; de lo contrario, pattern
se interpreta como un patrón ustring.
self : assertNotStringContains ( "foo" , "foobar" ) -- falla self : assertNotStringContains ( "foo" , "fobar" ) -- pasa self : assertNotStringContains ( ".oo" , "foobar" ) -- falla: coincide con "foo" self : assertNotStringContains ( ".oo" , "foobar" , true ) -- pasa: . se interpreta como un carácter literal
self : assertEquals ( esperado , actual , mensaje )
Esto prueba si el primer parámetro es igual al segundo parámetro. Si ambos parámetros son números, los valores se comparan utilizando assertWithinDelta
delta 1e-8 (0,00000001), ya que los números se representan como puntos flotantes con precisión limitada.
self : assertEquals ( 4 , calculadora . add ( 2 , 2 ))
self : assertNotEquals ( esperado , actual , mensaje )
Esto prueba si el primer parámetro no es igual al segundo parámetro. Si ambos parámetros son números, los valores se comparan utilizando assertNotWithinDelta
delta 1e-8 (0,00000001), ya que los números se representan como puntos flotantes con precisión limitada.
yo mismo : assertNotEquals ( 5 , calculadora . add ( 2 , 2 ))
self : assertWithinDelta ( esperado , actual , delta , mensaje )
Para dos números, esto prueba si el primero está dentro de una distancia dada (delta) del segundo. Esto es útil para comparar números de punto flotante , que se utilizan para representar números en la instalación estándar de Lua. (Para ser precisos, utiliza números de punto flotante de doble precisión ). Por ejemplo, en la versión de Scribunto instalada en la Wikipedia en inglés, la expresión 0.3 – 0.2 == 0.1
se evalúa como false
. Esto se debe a que, en la práctica, la expresión 0.3 – 0.2
es igual a 0.09999999999999997780…
y el número 0.1
es igual a 0.10000000000000000555…
. El ligero error entre los dos significa que Lua no los considera iguales. Por lo tanto, para probar la igualdad entre dos números de punto flotante, deberíamos aceptar valores dentro de una pequeña distancia (delta) entre sí, no solo valores iguales. Tenga en cuenta que este problema no afecta a los números enteros, que se pueden representar exactamente utilizando números de punto flotante de doble precisión hasta valores de 2^53.
self : assertWithinDelta ( 0.1 , calculadora . restar ( 0.3 , 0.2 ), 1e-10 )
self : assertNotWithinDelta ( esperado , actual , delta , mensaje )
Para dos números, esto prueba si el primero no está dentro de una distancia dada (delta) del segundo. Esta prueba es la inversa de assertWithinDelta.
self : assertNotWithinDelta ( 0.1 , calculadora . restar ( 0.3 , 0.1 ), 1e-10 )
self : assertDeepEquals ( esperado , actual , mensaje )
Esto prueba si el primer parámetro es igual al segundo parámetro. Si los parámetros son tablas, se comparan de forma recursiva y se respetan sus metamétodos __eq.
yo mismo : assertDeepEquals ( tabla1 , tabla2 )
self : assertTemplateEquals ( esperado , plantilla , argumentos , mensaje )
Esto prueba si el primer parámetro es igual a una llamada de plantilla. El segundo parámetro es el nombre de la plantilla y el tercer parámetro es una tabla de argumentos de la plantilla.
self : assertTemplateEquals ( 4 , 'add' , { 2 , 2 }) -- verdadero si {{add|2|2}} es igual a 4
Tenga en cuenta que algunas etiquetas escritas en notación XML no se pueden probar correctamente; consulte la nota de la assertResultEquals
función a continuación.
self : assertResultEquals ( esperado , texto , mensaje )
Esto comprueba si el primer parámetro es igual a la expansión de cualquier wikitexto. El segundo parámetro puede ser cualquier wikitexto.
yo mismo : assertResultEquals ( 4 , '{{#invoke:Calculator|add|2|2}}' )
Tenga en cuenta que algunas etiquetas especiales escritas en notación XML, como <pre>
, y no se pueden comparar correctamente. Estas etiquetas se convierten en marcadores de franja<nowiki>
antes de que Lua las procese. Los marcadores de franja son únicos, incluso cuando se generan a partir de una entrada idéntica, por lo que cualquier prueba que pruebe la igualdad de estas etiquetas fallará. Esto también se aplica a las funciones y .<gallery>
<ref>
assertTemplateEquals
assertSameResult
self : assertSameResult ( texto1 , texto2 , mensaje )
Esto prueba si la expansión de una cadena de wikitexto dada es igual a la expansión de otra cadena de wikitexto. Esto puede ser útil para verificar que un módulo se comporta de la misma manera que una plantilla que pretende reemplazar.
yo mismo : assertSameResult ( '{{add|2|2}}' , '{{#invoke:Calculator|add|2|2}}' )
Tenga en cuenta que algunas etiquetas escritas en notación XML no se pueden probar correctamente; consulte la nota de la assertResultEquals
función anterior.
self : assertThrows ( fn , mensajeesperado , mensaje )
Esto prueba si una función dada genera una excepción. Si expectedMessage
no lo hace nil
, comprobará si se generó una excepción con el mensaje de error indicado.
------------------------------------------------------------------------------- -- Pruebas unitarias para Scribunto. ------------------------------------------------------------------------------- require ( 'strict' ) local DebugHelper = {} local ScribuntoUnit = {} -- La tabla cfg contiene todas las cadenas localizables y la configuración, para facilitar la transferencia de este módulo a otra wiki. local cfg = mw . loadData ( 'Module:ScribuntoUnit/config' ) ------------------------------------------------------------------------------- -- Concatena claves y valores, ideal para mostrar una plantilla o una tabla de argumentos de función del analizador. -- @param keySeparator une la clave y el valor (por defecto "=") -- @param separator une los diferentes pares clave-valor (por defecto ", ") -- @example concatWithKeys({a = 1, b = 2, c = 3}, ' => ', ', ') => "a => 1, b => 2, c => 3" -- función DebugHelper . concatWithKeys ( tabla , separadorclave , separador ) separadorclave = separadorclave o ' = ' separador = separador o ', ' local concatenado = '' local i = 1 local primero = verdadero local argumentos sin nombre = verdadero para k , v en pares ( tabla ) hacer si primero entonces primero = falso de lo contrario concatenado = concatenado .. separador fin si k == i y argumentos sin nombre entonces i = i + 1 concatenado = concatenado .. tostring ( v ) de lo contrario argumentos sin nombre = falso concatenado = concatenado .. tostring ( k ) .. separadorclave .. tostring ( v ) fin fin devuelve concatenado fin ------------------------------------------------------------------------------- -- Compara dos tablas recursivamente (los valores que no son de tabla también se manejan correctamente). -- @param ignoreMetatable si es falso, se usa t1.__eq para la comparación -- function DebugHelper . deepCompare ( t1 , t2 , ignoreMetatable ) local type1 = type ( t1 ) local type2 = type ( t2 ) si type1 ~= type2 entonces devuelve falso fin si type1 ~= 'table' entonces devuelve t1 == t2 fin local metatable = getmetatable ( t1 ) si no ignoreMetatable y metatable y metatable . __eq entonces devuelve t1 == t2 fin para k1 , v1 en pares ( t1 ) hacer local v2 = t2 [ k1 ] si v2 == nil o no DebugHelper . deepCompare ( v1 , v2 ) entonces devuelve falso fin fin para k2 , v2 en pares ( t2 ) hacer si t1 [ k2 ] == nil entonces devuelve falso fin fin devuelve verdadero fin ------------------------------------------------------------------------------- -- Genera un error con información de la pila -- @param detalla una tabla con detalles del error -- - debe tener una clave 'text' que es el mensaje de error a mostrar -- - se agregará una clave 'trace' con los datos de la pila -- - y una clave 'source' con el número de archivo/línea -- - se agregará una metatabla para el manejo de errores -- function DebugHelper . raise ( detalles , nivel ) nivel = ( nivel o 1 ) + 1 detalles . trace = debug. traceback ( '' , nivel ) detalles . source = string. match ( detalles . trace , '^%s*stack traceback:%s*(%S*: )' ) -- setmetatable(detalles, { -- __tostring: function() return detalles. text fin -- }) error ( detalles , nivel ) fin ------------------------------------------------------------------------------- -- cuando se usa en una prueba, esa prueba se ignora y el conteo de omisiones aumenta en uno. -- función ScribuntoUnit : markTestSkipped () DebugHelper . raise ({ ScribuntoUnit = true , skipped = true }, 3 ) fin ------------------------------------------------------------------------------- -- Fallar una prueba incondicionalmente -- @param message descripción opcional de la prueba -- función ScribuntoUnit : fail ( message ) DebugHelper . raise ({ ScribuntoUnit = true , text = "La prueba falló" , message = message }, 2 ) end ------------------------------------------------------------------------------- -- Comprueba que la entrada sea verdadera -- @param message descripción opcional de la prueba -- function ScribuntoUnit : assertTrue ( actual , message ) if not actual then DebugHelper . raise ({ ScribuntoUnit = true , text = string.format ( "No se pudo afirmar que %s es verdadero" , tostring ( actual )), message = message }, 2 ) end fin ------------------------------------------------------------------------------- -- Comprueba que la entrada es falsa -- @param mensaje descripción opcional de la prueba -- función ScribuntoUnit : assertFalse ( actual , message ) si es actual entonces DebugHelper.raise ({ ScribuntoUnit = true , text = string.format ( "No se pudo afirmar que %s es falso" , tostring ( actual ) ), message = message }, 2 ) fin fin ------------------------------------------------------------------------------- -- Comprueba que una cadena de entrada contiene la cadena esperada -- @param mensaje descripción opcional de la prueba -- @param simple la búsqueda se realiza con una cadena simple en lugar de una ustring patrón -- función ScribuntoUnit : assertStringContains ( patrón , s , simple , mensaje ) si es tipo ( patrón ) ~= 'cadena' entonces DebugHelper . raise ({ ScribuntoUnit = true , text = mw . ustring . format ( "Error de tipo de patrón (cadena esperada, se obtuvo %s)" , type ( patrón )), message = message }, 2 ) end if type ( s ) ~= 'string' then DebugHelper . raise ({ ScribuntoUnit = true , text = mw . ustring . format ( "Error de tipo de cadena (cadena esperada, se obtuvo %s)" , type ( s )), message = message }, 2 ) end if not mw . ustring . find ( s , patrón , nulo , plain ) entonces DebugHelper . raise ({ ScribuntoUnit = true , text = mw . ustring . format ( 'No se pudo encontrar %s "%s" en la cadena "%s"' , plain y "cadena simple" o "patrón" , patrón , s ), mensaje = mensaje }, 2 ) fin fin ------------------------------------------------------------------------------- -- Comprueba que una cadena de entrada no contenga la cadena esperada -- @param mensaje descripción opcional de la prueba -- @param simple la búsqueda se realiza con una cadena simple en lugar de un patrón ustring -- función ScribuntoUnit : assertNotStringContains ( patrón , s , plain , mensaje ) si tipo ( patrón ) ~= 'cadena' entonces DebugHelper . raise ({ ScribuntoUnit = true , text = mw . ustring . format ( "Error de tipo de patrón (cadena esperada, se obtuvo %s)" , type ( patrón )), message = message }, 2 ) end if type ( s ) ~= 'string' then DebugHelper . raise ({ ScribuntoUnit = true , text = mw . ustring . format ( "Error de tipo de cadena (cadena esperada, se obtuvo %s)" , type ( s )), message = message }, 2 ) end local i , j = mw . ustring . find ( s , patrón , nil , plain ) if i then local match = mw . ustring . sub ( s , i , j ) DebugHelper . raise ({ ScribuntoUnit = true , text = mw . ustring . format ( 'Se encontró coincidencia "%s" para %s "%s"' , match , plain y "cadena simple" o "patrón" , patrón ), message = message }, 2 ) end end ------------------------------------------------------------------------------- -- Comprueba que una entrada tiene el valor esperado. -- @param message descripción opcional de la prueba -- @example assertEquals(4, add(2,2), "2+2 debería ser 4") -- function ScribuntoUnit : assertEquals ( esperado , actual , mensaje ) if type ( esperado ) == 'número' and type ( actual ) == 'número' then self : assertWithinDelta ( esperado , actual , 1e-8 , mensaje ) elseif esperado ~= actual then DebugHelper . raise ({ ScribuntoUnit = true , text = string.format ( "No se pudo afirmar que %s es igual al esperado %s" , tostring ( actual ), tostring ( esperado )), actual = actual , esperado = esperado , mensaje = mensaje , }, 2 ) end end ------------------------------------------------------------------------------- -- Comprueba que una entrada no tiene el valor esperado. -- @param message descripción opcional de la prueba -- @example assertNotEquals(5, add(2,2), "2+2 no debe ser 5") -- function ScribuntoUnit : assertNotEquals ( esperado , actual , mensaje ) si tipo ( esperado ) == 'número' y tipo ( actual ) == ' número' entonces auto : assertNotWithinDelta ( esperado , actual , 1e-8 , mensaje ) de lo contrario, si esperado == actual entonces DebugHelper.raise ({ ScribuntoUnit = true , texto = string.format ( "No se pudo afirmar que %s no es igual al esperado %s" , tostring ( actual ), tostring ( esperado )), actual = actual , esperado = esperado , mensaje = mensaje , }, 2 ) fin fin ------------------------------------------------------------------------------- -- Valida que tanto el valor esperado como el real sean números -- @param mensaje descripción opcional de la prueba -- función local validationNumbers ( esperado , actual , mensaje ) si tipo ( esperado ) ~= "número" entonces DebugHelper . raise ({ ScribuntoUnit = true , text = string.format ( "El valor esperado %s no es un número" , tostring ( esperado )), actual = actual , esperado = esperado , mensaje = mensaje , }, 3 ) end if type ( actual ) ~= "número" then DebugHelper . raise ({ ScribuntoUnit = true , text = string.format ( "El valor real %s no es un número" , tostring ( actual )), actual = actual , esperado = esperado , mensaje = mensaje , }, 3 ) fin fin ------------------------------------------------------------------------------- -- Comprueba que 'actual' está dentro de 'delta' de 'esperado'. -- @param mensaje descripción opcional de la prueba -- @ejemplo assertWithinDelta(1/3, 3/9, 0.000001, "3/9 debe ser 1/3") función ScribuntoUnit : assertWithinDelta ( esperado , actual , delta , mensaje ) validarNumbers ( esperado , actual , mensaje ) diff local = esperado - actual si diff < 0 entonces diff = - diff fin -- en lugar de importar math.abs si diff > delta entonces DebugHelper . raise ({ ScribuntoUnit = true , text = string.format ( "No se pudo afirmar que %f está dentro de %f del esperado %f" , actual , delta , esperado ), actual = actual , esperado = esperado , mensaje = mensaje , }, 2 ) end end ------------------------------------------------------------------------------- -- Comprueba que 'actual' no está dentro de 'delta' de 'esperado'. -- @param message descripción opcional de la prueba -- @example assertNotWithinDelta(1/3, 2/3, 0.000001, "1/3 no debería ser 2/3") function ScribuntoUnit : assertNotWithinDelta ( esperado , actual , delta , mensaje ) validationNumbers ( esperado , actual , mensaje ) local diff = esperado - actual if diff < 0 then diff = - diff end -- en lugar de importar math.abs si diff <= delta entonces DebugHelper.raise ({ ScribuntoUnit = true , text = string.format ( "No se pudo afirmar que %f no está dentro de %f del %f esperado" , actual , delta , esperado ) , actual = actual , esperado = esperado , message = message , } , 2 ) fin fin ------------------------------------------------------------------------------- -- Comprueba que una tabla tiene el valor esperado (incluidas las subtablas). -- @param message descripción opcional de la prueba -- @example assertDeepEquals({{1,3} , {2,4}} , partición(odd, {1,2,3,4})) función ScribuntoUnit : assertDeepEquals ( esperado , actual , mensaje ) si no DebugHelper.deepCompare ( esperado , actual ) entonces si tipo ( esperado ) == 'tabla' entonces esperado = mw . dumpObject ( esperado ) fin si tipo ( actual ) == 'tabla' entonces actual = mw . dumpObject ( actual ) fin DebugHelper . raise ({ ScribuntoUnit = true , texto = string. formato ( "No se pudo afirmar que %s es igual al esperado %s" , tostring ( actual ), tostring ( esperado )), actual = actual , esperado = esperado , mensaje = mensaje , }, 2 ) fin fin ------------------------------------------------------------------------------- -- Comprueba que un wikitexto da el resultado esperado después del procesamiento. -- @param message descripción opcional de la prueba -- @example assertResultEquals("Hola mundo", "{{concat|Hola|mundo}}") function ScribuntoUnit : assertResultEquals ( esperado , texto , mensaje ) local frame = self.frame local actual = frame : preprocess ( texto ) si esperado ~= actual entonces DebugHelper.raise ( { ScribuntoUnit = true , texto = string.format ( "No se pudo afirmar que %s es igual a esperado %s después del preprocesamiento" , texto , tostring ( esperado ) ) , actual = actual , actualRaw = texto , esperado = esperado , mensaje = mensaje , } , 2 ) fin fin ------------------------------------------------------------------------------- -- Comprueba que dos wikitextos den el mismo resultado después del procesamiento. -- @param message descripción opcional de la prueba -- @example assertSameResult("{{concat|Hola|mundo}}", "{{deleteLastChar|¡Hola mundo!}}") function ScribuntoUnit : assertSameResult ( text1 , text2 , message ) local frame = self . frame local processing1 = frame : preprocess ( text1 ) local processing2 = frame : preprocess ( text2 ) if processing1 ~= processing2 then DebugHelper . raise ({ ScribuntoUnit = true , text = string. formate ( "No se pudo afirmar que %s es igual al %s esperado después del preprocesamiento" , processing1 , processing2 ), actual = processing1 , actualRaw = text1 , esperado = procesado2 , esperadoRaw = texto2 , mensaje = mensaje , }, 2 ) fin fin ------------------------------------------------------------------------------- -- Comprueba que una función de analizador proporcione la salida esperada. -- @param mensaje descripción opcional de la prueba -- @ejemplo assertParserFunctionEquals("Hola mundo", "msg: concat ", {"Hola", " mundo"}) función ScribuntoUnit : assertParserFunctionEquals ( esperado , pfname , args , mensaje ) marco local = self.marco local actual = marco : callParserFunction { nombre = pfname , args = args } si esperado ~ = actual entonces DebugHelper . raise ({ ScribuntoUnit = true , text = string.format ( "No se pudo afirmar que %s con argumentos %s es igual al esperado %s después del preprocesamiento" , DebugHelper . concatWithKeys ( args ), pfname , expected ), actual = actual , actualRaw = pfname , expected = expected , message = message , }, 2 ) end end ------------------------------------------------------------------------------- -- Comprueba que una plantilla proporcione el resultado esperado. -- @param message descripción opcional de la prueba -- @example assertTemplateEquals("Hola mundo", "concat", {"Hola", " mundo"}) function ScribuntoUnit : assertTemplateEquals ( expected , template , args , message ) local frame = self . frame local actual = frame : expandTemplate { title = template , args = args } si se esperaba ~= actual entonces DebugHelper . raise ({ ScribuntoUnit = true , text = string. format ( "No se pudo afirmar que %s con argumentos %s es igual al esperado %s después del preprocesamiento" , DebugHelper . concatWithKeys ( args ), plantilla , esperado ), actual = actual , actualRaw = plantilla , esperado = esperado , mensaje = mensaje , }, 2 ) fin fin ------------------------------------------------------------------------------- -- Comprueba si una función genera un error -- @param fn la función a probar -- @param expectedMessage opcional el mensaje de error esperado -- @param message opcional descripción de la función de prueba ScribuntoUnit : assertThrows ( fn , expectedMessage , mensaje ) local exitoso , actualMessage = pcall ( fn ) si es exitoso entonces DebugHelper . raise ({ ScribuntoUnit = true , text = 'Se esperaba una excepción pero no se lanzó ninguna' , message = message , }, 2 ) end -- Para cadenas, elimina el número de línea agregado al mensaje de error actualMessage = type ( actualMessage ) == 'string' and string.match ( actualMessage , 'Module:[^:]*:[0-9]*: (.*)' ) or actualMessage local messagesMatch = DebugHelper . deepCompare ( expectedMessage , actualMessage ) if expectedMessage and not messagesMatch then DebugHelper . raise ({ ScribuntoUnit = true , expected = expectedMessage , actual = actualMessage , text = string.format ( 'Se esperaba una excepción con el mensaje %s, pero se obtuvo el mensaje %s' , tostring ( esperatedMessage ), tostring ( actualMessage ) ), message = message }, 2 ) end end ------------------------------------------------------------------------------- -- Comprueba si una función no genera un error -- @param fn la función a probar -- @param message descripción opcional de la función de prueba ScribuntoUnit : assertDoesNotThrow ( fn , message ) local successfullyed , actualMessage = pcall ( fn ) if successfully then return end -- Para cadenas, elimina el número de línea añadido al mensaje de error actualMessage = type ( actualMessage ) == 'string' and string.match ( actualMessage , 'Module:[^:]*:[0-9]*: (.*)' ) or actualMessage DebugHelper . raise ({ ScribuntoUnit = true , actual = actualMessage , text = string.format ( 'No se esperaba ninguna excepción, pero se obtuvo una excepción con el mensaje %s' , tostring ( actualMessage ) ), message = message }, 2 ) end ------------------------------------------------------------------------------- -- Crea una nueva suite de pruebas. -- @param o una tabla con funciones de prueba (alternativamente, las funciones se pueden agregar más tarde a la suite devuelta) -- function ScribuntoUnit : new ( o ) o = o or {} o . _tests = {} setmetatable ( o , { __index = self , __newindex = function ( t , k , v ) if type ( k ) == "string" and k : find ( '^test' ) and type ( v ) == "function" then -- Almacena las funciones de prueba en el orden en que fueron definidas table.insert ( o . _tests , { name = k , test = v }) else rawset ( t , k , v ) end end }) o . run = function ( frame ) return self : run ( o , frame ) end return o end ------------------------------------------------------------------------------- -- Restablece los contadores globales -- function ScribuntoUnit : init ( frame ) self . frame = frame o mw . getCurrentFrame () self . successCount = 0 self . failureCount = 0 self . skipCount = 0 self . resultados = {} fin ------------------------------------------------------------------------------- -- Ejecuta un solo caso de prueba -- @param nombre prueba número -- @param función de prueba que contiene afirmaciones -- función ScribuntoUnit : runTest ( suite , nombre , prueba ) local success , detalles = pcall ( prueba , suite ) si success entonces self . successCount = self . successCount + 1 table.insert ( self . resultados , { nombre = nombre , éxito = verdadero } ) elseif tipo ( detalles ) ~ = ' tabla ' o no detalles . ScribuntoUnit entonces -- un error real , no una aserción fallida self.failureCount = self.failureCount + 1 tabla.insert ( self.resultados , { nombre = nombre , error = verdadero , mensaje = ' Error de Lua -- ' .. tostring ( detalles ) } ) elseif detalles.skipped entonces self.skipCount = self.skipCount + 1 tabla.insert ( self.resultados , { nombre = nombre , skipped = verdadero } ) else self.failureCount = self.failureCount + 1 mensaje local = detalles.fuente o " " si detalles.mensaje entonces mensaje = mensaje .. detalles.mensaje .. " \ n " fin mensaje = mensaje .. detalles . text table.insert ( self.results , { name = name , error = true , message = message , expected = details.esperate , actual = details.actual , testname = details.message }) end end ------------------------------------------------------------------------------- -- Ejecuta todas las pruebas y muestra los resultados . -- function ScribuntoUnit : runSuite ( suite , frame ) self : init ( frame ) for i , testDetails in ipairs ( suite . _tests ) do self : runTest ( suite , testDetails . name , testDetails . test ) end return { successCount = self . successCount , failureCount = self . failureCount , skipCount = self . skipCount , results = self . results , } end ------------------------------------------------------------------------------- -- #invoke punto de entrada para ejecutar las pruebas. -- Se puede llamar sin un marco, en cuyo caso usará mw.log para la salida -- @param displayMode see displayResults() -- function ScribuntoUnit : run ( suite , frame ) local testData = self : runSuite ( suite , frame ) if frame y frame . args entonces devuelve self : displayResults ( testData , frame.args.displayMode o 'table' ) de lo contrario devuelve self : displayResults ( testData , ' log' ) fin fin ------------------------------------------------------------------------------- -- Muestra los resultados de la prueba -- @param displayMode : 'table', 'log ' o 'short' -- función ScribuntoUnit : displayResults ( testData , displayMode ) si displayMode == ' table' entonces devuelve self : displayResultsAsTable ( testData ) elseif displayMode == 'log' then return self : displayResultsAsLog ( testData ) elseif displayMode == 'short' then return self : displayResultsAsShort ( testData ) else error ( 'modo de visualización desconocido' ) end end function ScribuntoUnit : displayResultsAsLog ( testData ) if testData . failureCount > 0 then mw . log ( '¡FALLAS!' ) elseif testData . skipCount > 0 then mw . log ( 'Algunas pruebas no se pudieron ejecutar sin un marco y se omitieron. Invoque este conjunto de pruebas como plantilla para ejecutar todas las pruebas.' ) end mw . log ( string.format ( 'Afirmaciones: éxito: %d, error: %d, omitido: %d' , testData . successCount , testData . failureCount , testData . skipCount )) mw . log ( '-------------------------------------------------------------------------------' ) para _ , resultado en ipairs ( testData . results ) hacer si resultado . error entonces mw . log ( string. formato ( '%s: %s' , resultado . nombre , resultado . mensaje )) fin fin fin función ScribuntoUnit : displayResultsAsShort ( testData ) texto local = string. formato ( cfg . shortResultsFormat , testData . successCount , testData . failureCount , testData . skipCount ) si testData.failureCount > 0 entonces texto = ' < span class = " error " > ' .. texto .. ' </span> ' fin devolver texto fin función ScribuntoUnit : displayResultsAsTable ( testData ) iconoExito local , IconoExito = self.frame : preproceso ( cfg.successIndicator ) , self.frame : preproceso ( cfg.failureIndicator ) texto local = ' ' si testData.failureCount > 0 entonces local msg = mw.message.newRawMessage ( cfg.failureSummary , testData.failureCount ) : plain ( ) msg = self.frame : preproceso ( msg ) si cfg.failureCategory entonces msg = cfg . failureCategory .. msg end text = texto .. failIcon .. ' ' .. msg .. ' \n ' else text = texto .. successIcon .. ' ' .. cfg . successSummary .. ' \n ' end text = texto .. '{| class="wikitable scribunto-test-table" \n ' text = texto .. '! \n ! ' .. cfg . nameString .. ' \n ! ' .. cfg . expectedString .. ' \n ! ' .. cfg . actualString ..' \n ' para _ , resultado en ipairs ( testData . results ) hacer texto = texto .. '|- \n ' si resultado . error entonces texto = texto .. '| ' .. failIcon .. ' \n | ' si ( resultado . esperado y resultado . actual ) entonces nombre local = resultado . nombre si resultado . nombreprueba entonces nombre = nombre .. ' / ' .. resultado . nombreprueba fin texto = texto .. mw . texto . nowiki ( nombre ) .. ' \n | ' .. mw . texto . nowiki ( tostring ( resultado . esperado )) .. ' \n | ' .. mw . texto . nowiki ( tostring ( resultado . actual )) .. ' \n ' de lo contrario texto = texto .. mw . texto . nowiki ( resultado . nombre ) .. ' \n | ' .. ' colspan="2" | ' .. mw . texto . nowiki ( resultado . mensaje ) .. ' \n ' fin de lo contrario texto = texto .. '| ' .. successIcon .. ' \n | ' .. mw . texto . nowiki ( resultado . nombre ) .. ' \n | \n | \n ' fin fin texto = texto .. '|} \n ' devolver texto fin devolver ScribuntoUnit