Jump to content
Wikipedia The Free Encyclopedia

Module:ScribuntoUnit

From Wikipedia, the free encyclopedia
Module documentation[view] [edit] [history] [purge]

This module provides unit tests for other Lua modules. To test a module, you must create a separate test module, usually located at Module:Module name/testcases. The module is tested with the ScribuntoUnit module, which verifies that the operations defined in the test module produce the expected results.

Test module structure

[edit ]

To make a test module (test suite), start with the following code:

localmyModule=require('Module:MyModule')-- the module to be tested
localScribuntoUnit=require('Module:ScribuntoUnit')
localsuite=ScribuntoUnit:new()

After you have done this you can add individual test functions to the suite object. Any function that begins with test is treated as a test. (Other functions will be ignored by ScribuntoUnit, but can be used in the tests themselves.)

functionsuite:testSomeCall()
self:assertEquals('expected value',myModule.someCall(123))
self:assertEquals('other expected value',myModule.someCall(456))
end
functionsuite:testSomeOtherCall()
self:assertEquals('expected value',myModule.someOtherCall(123))
self:assertEquals('other expected value',myModule.someOtherCall(456))
end

The tests you write should make assertions, and ScribuntoUnit will check whether those assertions are true. For example, assertEquals checks that both of the arguments it is given are equal. If ScribuntoUnit doesn't find an assertion to be true, then the test will fail and an error message will be generated. The error message will show which assertion failed verification (other checks on the assertions are not made at this time).

To finish the test module, you need to return the suite object.

returnsuite

Running the tests

[edit ]

The tests can be run in two ways: through the Lua debug console, and from a wiki page using #invoke. If you are running the tests through the debug console, use the code require('Module:MyModule/testcases').run(). If you are running them from a wiki page, use the code {{#invoke:MyModule/testcases|run}}. This will generate a table containing the results. It is also possible to display a more compact table by using the code {{#invoke:MyModule/testcases|run|displayMode=short}}.

Tests

[edit ]

Error messages

[edit ]

The last parameter of all the test methods is a message that is displayed if validation fails.

self:assertEquals("expected value",myModule.someCall(123),"The call to myModule.someCall(123) didn't return the expected value.")

fail

[edit ]
self:fail(message)

Unconditionally fails a test.

self:fail("Test failed because of X.")

assertTrue, assertFalse

[edit ]
self:assertTrue(expression,message)
self:assertFalse(expression,message)

These test whether the given expression evaluates to true or false. Note that in Lua false and nil evaluate to false, and everything else evaluates to true.

self:assertTrue(2+2==4)
self:assertTrue('foo')
self:assertFalse(2+2==5)
self:assertFalse(nil)

assertStringContains

[edit ]
self:assertStringContains(pattern,s,plain,message)

This tests whether pattern is found in the string s. If plain is true, then pattern is interpreted as literal text; otherwise, pattern is interpreted as a ustring pattern.

If the string is not found, the error message shows the values of pattern and s; if s is more than 70 characters long then a truncated version is displayed. This method is useful for testing specific behaviours in complex wikitext.

self:assertStringContains("foo","foobar")-- passes
self:assertStringContains("foo","fobar")-- fails
self:assertStringContains(".oo","foobar")-- passes: matches "foo"
self:assertStringContains(".oo","foobar",true)-- fails: . is interpreted as a literal character

assertNotStringContains

[edit ]
self:assertNotStringContains(pattern,s,plain,message)

This is the opposite of assertStringContains. The test will fail if pattern is found in the string s. If plain is true, then pattern is interpreted as literal text; otherwise, pattern is interpreted as a ustring pattern.

self:assertNotStringContains("foo","foobar")-- fails
self:assertNotStringContains("foo","fobar")-- passes
self:assertNotStringContains(".oo","foobar")-- fails: matches "foo"
self:assertNotStringContains(".oo","foobar",true)-- passes: . is interpreted as a literal character

assertEquals

[edit ]
self:assertEquals(expected,actual,message)

This tests whether the first parameter is equal to the second parameter. If both parameters are numbers, the values are instead compared using assertWithinDelta with delta 1e-8 (0.00000001) since numbers are represented as floating points with limited precision.

self:assertEquals(4,calculator.add(2,2))

assertNotEquals

[edit ]
self:assertNotEquals(expected,actual,message)

This tests whether the first parameter is not equal to the second parameter. If both parameters are numbers, the values are instead compared using assertNotWithinDelta with delta 1e-8 (0.00000001) since numbers are represented as floating points with limited precision.

self:assertNotEquals(5,calculator.add(2,2))

assertWithinDelta

[edit ]
self:assertWithinDelta(expected,actual,delta,message)

For two numbers, this tests whether the first is within a given distance (delta) from the second. This is useful to compare floating point numbers, which are used to represent numbers in the standard installation of Lua. (To be precise, it uses double-precision floating point numbers.) For example, on the version of Scribunto installed on the English Wikipedia, the expression 0.3 – 0.2 == 0.1 evaluates to false. This is because in practice, the expression 0.3 – 0.2 equals 0.09999999999999997780... and the number 0.1 equals 0.10000000000000000555.... The slight error between the two means that Lua does not consider them equal. Therefore, to test for equality between two floating point numbers, we should accept values within a small distance (delta) of each other, not just equal values. Note that this problem does not affect integers, which can be represented exactly using double-precision floating point numbers up to values of 2^53.

self:assertWithinDelta(0.1,calculator.subtract(0.3,0.2),1e-10)

assertNotWithinDelta

[edit ]
self:assertNotWithinDelta(expected,actual,delta,message)

For two numbers, this tests whether the first is not within a given distance (delta) from the second. This test is the inverse of assertWithinDelta.

self:assertNotWithinDelta(0.1,calculator.subtract(0.3,0.1),1e-10)

assertDeepEquals

[edit ]
self:assertDeepEquals(expected,actual,message)

This tests whether the first parameter is equal to the second parameter. If the parameters are tables, they are compared recursively, and their __eq metamethods are respected.

self:assertDeepEquals(table1,table2)

assertTemplateEquals

[edit ]
self:assertTemplateEquals(expected,template,args,message)

This tests whether the first parameter equals a template call. The second parameter is the template name, and the third parameter is a table of the template arguments.

self:assertTemplateEquals(4,'add',{2,2})-- true if {{add|2|2}} equals 4

Note that some tags written in XML notation cannot be tested correctly; see the note for the assertResultEquals function below.

assertResultEquals

[edit ]
self:assertResultEquals(expected,text,message)

This tests whether the first parameter equals the expansion of any wikitext. The second parameter can be any wikitext.

self:assertResultEquals(4,'{{#invoke:Calculator|add|2|2}}')

Note that some special tags written in XML notation, such as <pre>, <nowiki>, <gallery> and <ref> cannot be compared correctly. These tags are converted to strip markers before they are processed by Lua. Strip markers are unique, even when generated from identical input, so any tests testing these tags for equality will fail. This also applies to the assertTemplateEquals and assertSameResult functions.

assertSameResult

[edit ]
self:assertSameResult(text1,text2,message)

This tests whether the expansion of a given string of wikitext equals the expansion of another string of wikitext. This can be useful for verifying that a module behaves in the same way as a template it is intended to replace.

self:assertSameResult('{{add|2|2}}','{{#invoke:Calculator|add|2|2}}')

Note that some tags written in XML notation cannot be tested correctly; see the note for the assertResultEquals function above.

assertThrows

[edit ]
self:assertThrows(fn,expectedMessage,message)

This tests whether a given function throws an exception. If expectedMessage is not nil, it will check that an exception was thrown with the given error message.

See also

[edit ]
The above documentation is transcluded from Module:ScribuntoUnit/doc. (edit | history)
Editors can experiment in this module's sandbox (edit | diff) and testcases (edit | run) pages.
Subpages of this module.

 -------------------------------------------------------------------------------
 -- Unit tests for Scribunto.
 -------------------------------------------------------------------------------
 require('strict')

 localDebugHelper={}
 localScribuntoUnit={}

 -- The cfg table contains all localisable strings and configuration, to make it
 -- easier to port this module to another wiki.
 localcfg=mw.loadData('Module:ScribuntoUnit/config')

 -------------------------------------------------------------------------------
 -- Concatenates keys and values, ideal for displaying a template or parser function argument table.
 -- @param keySeparator glue between key and value (defaults to " = ")
 -- @param separator glue between different key-value pairs (defaults to ", ")
 -- @example concatWithKeys({a = 1, b = 2, c = 3}, ' => ', ', ') => "a => 1, b => 2, c => 3"
 -- 
 functionDebugHelper.concatWithKeys(table,keySeparator,separator)
 keySeparator=keySeparatoror' = '
 separator=separatoror', '
 localconcatted=''
 locali=1
 localfirst=true
 localunnamedArguments=true
 fork,vinpairs(table)do
 iffirstthen
 first=false
 else
 concatted=concatted..separator
 end
 ifk==iandunnamedArgumentsthen
 i=i+1
 concatted=concatted..tostring(v)
 else
 unnamedArguments=false
 concatted=concatted..tostring(k)..keySeparator..tostring(v)
 end
 end
 returnconcatted
 end

 -------------------------------------------------------------------------------
 -- Compares two tables recursively (non-table values are handled correctly as well).
 -- @param ignoreMetatable if false, t1.__eq is used for the comparison
 -- 
 functionDebugHelper.deepCompare(t1,t2,ignoreMetatable)
 localtype1=type(t1)
 localtype2=type(t2)

 iftype1~=type2then
 returnfalse
 end
 iftype1~='table'then
 returnt1==t2
 end

 localmetatable=getmetatable(t1)
 ifnotignoreMetatableandmetatableandmetatable.__eqthen
 returnt1==t2
 end

 fork1,v1inpairs(t1)do
 localv2=t2[k1]
 ifv2==nilornotDebugHelper.deepCompare(v1,v2)then
 returnfalse
 end
 end
 fork2,v2inpairs(t2)do
 ift1[k2]==nilthen
 returnfalse
 end
 end

 returntrue
 end

 -------------------------------------------------------------------------------
 -- Raises an error with stack information
 -- @param details a table with error details
 -- - should have a 'text' key which is the error message to display
 -- - a 'trace' key will be added with the stack data
 -- - and a 'source' key with file/line number
 -- - a metatable will be added for error handling
 -- 
 functionDebugHelper.raise(details,level)
 level=(levelor1)+1
 details.trace=debug.traceback('',level)
 details.source=string.match(details.trace,'^%s*stack traceback:%s*(%S*: )')

 -- setmetatable(details, {
 -- __tostring: function() return details.text end
 -- })

 error(details,level)
 end

 -------------------------------------------------------------------------------
 -- when used in a test, that test gets ignored, and the skipped count increases by one.
 -- 
 functionScribuntoUnit:markTestSkipped()
 DebugHelper.raise({ScribuntoUnit=true,skipped=true},3)
 end

 -------------------------------------------------------------------------------
 -- Unconditionally fail a test
 -- @param message optional description of the test
 -- 
 functionScribuntoUnit:fail(message)
 DebugHelper.raise({ScribuntoUnit=true,text="Test failed",message=message},2)
 end

 -------------------------------------------------------------------------------
 -- Checks that the input is true
 -- @param message optional description of the test
 -- 
 functionScribuntoUnit:assertTrue(actual,message)
 ifnotactualthen
 DebugHelper.raise({ScribuntoUnit=true,text=string.format("Failed to assert that %s is true",tostring(actual)),message=message},2)
 end
 end

 -------------------------------------------------------------------------------
 -- Checks that the input is false
 -- @param message optional description of the test
 -- 
 functionScribuntoUnit:assertFalse(actual,message)
 ifactualthen
 DebugHelper.raise({ScribuntoUnit=true,text=string.format("Failed to assert that %s is false",tostring(actual)),message=message},2)
 end
 end

 -------------------------------------------------------------------------------
 -- Checks an input string contains the expected string
 -- @param message optional description of the test
 -- @param plain search is made with a plain string instead of a ustring pattern
 -- 
 functionScribuntoUnit:assertStringContains(pattern,s,plain,message)
 iftype(pattern)~='string'then
 DebugHelper.raise({
 ScribuntoUnit=true,
 text=mw.ustring.format("Pattern type error (expected string, got %s)",type(pattern)),
 message=message
 },2)
 end
 iftype(s)~='string'then
 DebugHelper.raise({
 ScribuntoUnit=true,
 text=mw.ustring.format("String type error (expected string, got %s)",type(s)),
 message=message
 },2)
 end
 ifnotmw.ustring.find(s,pattern,nil,plain)then
 DebugHelper.raise({
 ScribuntoUnit=true,
 text=mw.ustring.format('Failed to find %s "%s" in string "%s"',plainand"plain string"or"pattern",pattern,s),
 message=message
 },2)
 end
 end

 -------------------------------------------------------------------------------
 -- Checks an input string doesn't contain the expected string
 -- @param message optional description of the test
 -- @param plain search is made with a plain string instead of a ustring pattern
 -- 
 functionScribuntoUnit:assertNotStringContains(pattern,s,plain,message)
 iftype(pattern)~='string'then
 DebugHelper.raise({
 ScribuntoUnit=true,
 text=mw.ustring.format("Pattern type error (expected string, got %s)",type(pattern)),
 message=message
 },2)
 end
 iftype(s)~='string'then
 DebugHelper.raise({
 ScribuntoUnit=true,
 text=mw.ustring.format("String type error (expected string, got %s)",type(s)),
 message=message
 },2)
 end
 locali,j=mw.ustring.find(s,pattern,nil,plain)
 ifithen
 localmatch=mw.ustring.sub(s,i,j)
 DebugHelper.raise({
 ScribuntoUnit=true,
 text=mw.ustring.format('Found match "%s" for %s "%s"',match,plainand"plain string"or"pattern",pattern),
 message=message
 },2)
 end
 end

 -------------------------------------------------------------------------------
 -- Checks that an input has the expected value.
 -- @param message optional description of the test
 -- @example assertEquals(4, add(2,2), "2+2 should be 4")
 -- 
 functionScribuntoUnit:assertEquals(expected,actual,message)
 iftype(expected)=='number'andtype(actual)=='number'then
 self:assertWithinDelta(expected,actual,1e-8,message)
 elseifexpected~=actualthen
 DebugHelper.raise({
 ScribuntoUnit=true,
 text=string.format("Failed to assert that %s equals expected %s",tostring(actual),tostring(expected)),
 actual=actual,
 expected=expected,
 message=message,
 },2)
 end
 end

 -------------------------------------------------------------------------------
 -- Checks that an input does not have the expected value.
 -- @param message optional description of the test
 -- @example assertNotEquals(5, add(2,2), "2+2 should not be 5")
 -- 
 functionScribuntoUnit:assertNotEquals(expected,actual,message)
 iftype(expected)=='number'andtype(actual)=='number'then
 self:assertNotWithinDelta(expected,actual,1e-8,message)
 elseifexpected==actualthen
 DebugHelper.raise({
 ScribuntoUnit=true,
 text=string.format("Failed to assert that %s does not equal expected %s",tostring(actual),tostring(expected)),
 actual=actual,
 expected=expected,
 message=message,
 },2)
 end
 end

 -------------------------------------------------------------------------------
 -- Validates that both the expected and actual values are numbers
 -- @param message optional description of the test
 -- 
 localfunctionvalidateNumbers(expected,actual,message)
 iftype(expected)~="number"then
 DebugHelper.raise({
 ScribuntoUnit=true,
 text=string.format("Expected value %s is not a number",tostring(expected)),
 actual=actual,
 expected=expected,
 message=message,
 },3)
 end
 iftype(actual)~="number"then
 DebugHelper.raise({
 ScribuntoUnit=true,
 text=string.format("Actual value %s is not a number",tostring(actual)),
 actual=actual,
 expected=expected,
 message=message,
 },3)
 end
 end

 -------------------------------------------------------------------------------
 -- Checks that 'actual' is within 'delta' of 'expected'.
 -- @param message optional description of the test
 -- @example assertWithinDelta(1/3, 3/9, 0.000001, "3/9 should be 1/3")
 functionScribuntoUnit:assertWithinDelta(expected,actual,delta,message)
 validateNumbers(expected,actual,message)
 localdiff=expected-actual
 ifdiff<0thendiff=-diffend-- instead of importing math.abs
 ifdiff>deltathen
 DebugHelper.raise({
 ScribuntoUnit=true,
 text=string.format("Failed to assert that %f is within %f of expected %f",actual,delta,expected),
 actual=actual,
 expected=expected,
 message=message,
 },2)
 end
 end

 -------------------------------------------------------------------------------
 -- Checks that 'actual' is not within 'delta' of 'expected'.
 -- @param message optional description of the test
 -- @example assertNotWithinDelta(1/3, 2/3, 0.000001, "1/3 should not be 2/3")
 functionScribuntoUnit:assertNotWithinDelta(expected,actual,delta,message)
 validateNumbers(expected,actual,message)
 localdiff=expected-actual
 ifdiff<0thendiff=-diffend-- instead of importing math.abs
 ifdiff<=deltathen
 DebugHelper.raise({
 ScribuntoUnit=true,
 text=string.format("Failed to assert that %f is not within %f of expected %f",actual,delta,expected),
 actual=actual,
 expected=expected,
 message=message,
 },2)
 end
 end

 -------------------------------------------------------------------------------
 -- Checks that a table has the expected value (including sub-tables).
 -- @param message optional description of the test
 -- @example assertDeepEquals({{1,3}, {2,4}}, partition(odd, {1,2,3,4}))
 functionScribuntoUnit:assertDeepEquals(expected,actual,message)
 ifnotDebugHelper.deepCompare(expected,actual)then
 iftype(expected)=='table'then
 expected=mw.dumpObject(expected)
 end
 iftype(actual)=='table'then
 actual=mw.dumpObject(actual)
 end
 DebugHelper.raise({
 ScribuntoUnit=true,
 text=string.format("Failed to assert that %s equals expected %s",tostring(actual),tostring(expected)),
 actual=actual,
 expected=expected,
 message=message,
 },2)
 end
 end

 -------------------------------------------------------------------------------
 -- Checks that a wikitext gives the expected result after processing.
 -- @param message optional description of the test
 -- @example assertResultEquals("Hello world", "{{concat|Hello|world}}")
 functionScribuntoUnit:assertResultEquals(expected,text,message)
 localframe=self.frame
 localactual=frame:preprocess(text)
 ifexpected~=actualthen
 DebugHelper.raise({
 ScribuntoUnit=true,
 text=string.format("Failed to assert that %s equals expected %s after preprocessing",text,tostring(expected)),
 actual=actual,
 actualRaw=text,
 expected=expected,
 message=message,
 },2)
 end
 end

 -------------------------------------------------------------------------------
 -- Checks that two wikitexts give the same result after processing.
 -- @param message optional description of the test
 -- @example assertSameResult("{{concat|Hello|world}}", "{{deleteLastChar|Hello world!}}")
 functionScribuntoUnit:assertSameResult(text1,text2,message)
 localframe=self.frame
 localprocessed1=frame:preprocess(text1)
 localprocessed2=frame:preprocess(text2)
 ifprocessed1~=processed2then
 DebugHelper.raise({
 ScribuntoUnit=true,
 text=string.format("Failed to assert that %s equals expected %s after preprocessing",processed1,processed2),
 actual=processed1,
 actualRaw=text1,
 expected=processed2,
 expectedRaw=text2,
 message=message,
 },2)
 end
 end

 -------------------------------------------------------------------------------
 -- Checks that a parser function gives the expected output.
 -- @param message optional description of the test
 -- @example assertParserFunctionEquals("Hello world", "msg:concat", {"Hello", " world"})
 functionScribuntoUnit:assertParserFunctionEquals(expected,pfname,args,message)
 localframe=self.frame
 localactual=frame:callParserFunction{name=pfname,args=args}
 ifexpected~=actualthen
 DebugHelper.raise({
 ScribuntoUnit=true,
 text=string.format("Failed to assert that %s with args %s equals expected %s after preprocessing",
 DebugHelper.concatWithKeys(args),pfname,expected),
 actual=actual,
 actualRaw=pfname,
 expected=expected,
 message=message,
 },2)
 end
 end

 -------------------------------------------------------------------------------
 -- Checks that a template gives the expected output.
 -- @param message optional description of the test
 -- @example assertTemplateEquals("Hello world", "concat", {"Hello", " world"})
 functionScribuntoUnit:assertTemplateEquals(expected,template,args,message)
 localframe=self.frame
 localactual=frame:expandTemplate{title=template,args=args}
 ifexpected~=actualthen
 DebugHelper.raise({
 ScribuntoUnit=true,
 text=string.format("Failed to assert that %s with args %s equals expected %s after preprocessing",
 DebugHelper.concatWithKeys(args),template,expected),
 actual=actual,
 actualRaw=template,
 expected=expected,
 message=message,
 },2)
 end
 end

 -------------------------------------------------------------------------------
 -- Checks whether a function throws an error
 -- @param fn the function to test
 -- @param expectedMessage optional the expected error message
 -- @param message optional description of the test
 functionScribuntoUnit:assertThrows(fn,expectedMessage,message)
 localsucceeded,actualMessage=pcall(fn)
 ifsucceededthen
 DebugHelper.raise({
 ScribuntoUnit=true,
 text='Expected exception but none was thrown',
 message=message,
 },2)
 end
 -- For strings, strip the line number added to the error message
 actualMessage=type(actualMessage)=='string'
 andstring.match(actualMessage,'Module:[^:]*:[0-9]*: (.*)')
 oractualMessage
 localmessagesMatch=DebugHelper.deepCompare(expectedMessage,actualMessage)
 ifexpectedMessageandnotmessagesMatchthen
 DebugHelper.raise({
 ScribuntoUnit=true,
 expected=expectedMessage,
 actual=actualMessage,
 text=string.format('Expected exception with message %s, but got message %s',
 tostring(expectedMessage),tostring(actualMessage)
 ),
 message=message
 },2)
 end
 end

 -------------------------------------------------------------------------------
 -- Checks whether a function doesn't throw an error
 -- @param fn the function to test
 -- @param message optional description of the test
 functionScribuntoUnit:assertDoesNotThrow(fn,message)
 localsucceeded,actualMessage=pcall(fn)
 ifsucceededthen
 return
 end
 -- For strings, strip the line number added to the error message
 actualMessage=type(actualMessage)=='string'
 andstring.match(actualMessage,'Module:[^:]*:[0-9]*: (.*)')
 oractualMessage
 DebugHelper.raise({
 ScribuntoUnit=true,
 actual=actualMessage,
 text=string.format('Expected no exception, but got exception with message %s',
 tostring(actualMessage)
 ),
 message=message
 },2)
 end

 -------------------------------------------------------------------------------
 -- Creates a new test suite.
 -- @param o a table with test functions (alternatively, the functions can be added later to the returned suite)
 -- 
 functionScribuntoUnit:new(o)
 o=oor{}
 o._tests={}
 setmetatable(o,{
 __index=self,
 __newindex=function(t,k,v)
 iftype(k)=="string"andk:find('^test')andtype(v)=="function"then
 -- Store test functions in the order they were defined
 table.insert(o._tests,{name=k,test=v})
 else
 rawset(t,k,v)
 end
 end
 })
 o.run=function(frame)returnself:run(o,frame)end
 returno
 end

 -------------------------------------------------------------------------------
 -- Resets global counters
 -- 
 functionScribuntoUnit:init(frame)
 self.frame=frameormw.getCurrentFrame()
 self.successCount=0
 self.failureCount=0
 self.skipCount=0
 self.results={}
 end

 -------------------------------------------------------------------------------
 -- Runs a single testcase
 -- @param name test nume
 -- @param test function containing assertions
 -- 
 functionScribuntoUnit:runTest(suite,name,test)
 localsuccess,details=pcall(test,suite)

 ifsuccessthen
 self.successCount=self.successCount+1
 table.insert(self.results,{name=name,success=true})
 elseiftype(details)~='table'ornotdetails.ScribuntoUnitthen-- a real error, not a failed assertion
 self.failureCount=self.failureCount+1
 table.insert(self.results,{name=name,error=true,message='Lua error -- '..tostring(details)})
 elseifdetails.skippedthen
 self.skipCount=self.skipCount+1
 table.insert(self.results,{name=name,skipped=true})
 else
 self.failureCount=self.failureCount+1
 localmessage=details.sourceor""
 ifdetails.messagethen
 message=message..details.message.."\n"
 end
 message=message..details.text
 table.insert(self.results,{name=name,error=true,message=message,expected=details.expected,actual=details.actual,testname=details.message})
 end
 end

 -------------------------------------------------------------------------------
 -- Runs all tests and displays the results.
 -- 
 functionScribuntoUnit:runSuite(suite,frame)
 self:init(frame)
 fori,testDetailsinipairs(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 entry point for running the tests.
 -- Can be called without a frame, in which case it will use mw.log for output
 -- @param displayMode see displayResults()
 -- 
 functionScribuntoUnit:run(suite,frame)
 localtestData=self:runSuite(suite,frame)
 ifframeandframe.argsthen
 returnself:displayResults(testData,frame.args.displayModeor'table')
 else
 returnself:displayResults(testData,'log')
 end
 end

 -------------------------------------------------------------------------------
 -- Displays test results 
 -- @param displayMode: 'table', 'log' or 'short'
 -- 
 functionScribuntoUnit:displayResults(testData,displayMode)
 ifdisplayMode=='table'then
 returnself:displayResultsAsTable(testData)
 elseifdisplayMode=='log'then
 returnself:displayResultsAsLog(testData)
 elseifdisplayMode=='short'then
 returnself:displayResultsAsShort(testData)
 else
 error('unknown display mode')
 end
 end

 functionScribuntoUnit:displayResultsAsLog(testData)
 iftestData.failureCount>0then
 mw.log('FAILURES!!!')
 elseiftestData.skipCount>0then
 mw.log('Some tests could not be executed without a frame and have been skipped. Invoke this test suite as a template to run all tests.')
 end
 mw.log(string.format('Assertions: success: %d, error: %d, skipped: %d',testData.successCount,testData.failureCount,testData.skipCount))
 mw.log('-------------------------------------------------------------------------------')
 for_,resultinipairs(testData.results)do
 ifresult.errorthen
 mw.log(string.format('%s: %s',result.name,result.message))
 end
 end
 end

 functionScribuntoUnit:displayResultsAsShort(testData)
 localtext=string.format(cfg.shortResultsFormat,testData.successCount,testData.failureCount,testData.skipCount)
 iftestData.failureCount>0then
 text='<span class="error">'..text..'</span>'
 end
 returntext
 end

 functionScribuntoUnit:displayResultsAsTable(testData)
 localsuccessIcon,failIcon=self.frame:preprocess(cfg.successIndicator),self.frame:preprocess(cfg.failureIndicator)
 localtext=''
 iftestData.failureCount>0then
 localmsg=mw.message.newRawMessage(cfg.failureSummary,testData.failureCount):plain()
 msg=self.frame:preprocess(msg)
 ifcfg.failureCategorythen
 msg=cfg.failureCategory..msg
 end
 text=text..failIcon..' '..msg..'\n'
 else
 text=text..successIcon..' '..cfg.successSummary..'\n'
 end
 text=text..'{| class="wikitable scribunto-test-table"\n'
 text=text..'!\n! '..cfg.nameString..'\n! '..cfg.expectedString..'\n! '..cfg.actualString..'\n'
 for_,resultinipairs(testData.results)do
 text=text..'|-\n'
 ifresult.errorthen
 text=text..'| '..failIcon..'\n| '
 if(result.expectedandresult.actual)then
 localname=result.name
 ifresult.testnamethen
 name=name..' / '..result.testname
 end
 text=text..mw.text.nowiki(name)..'\n| '..mw.text.nowiki(tostring(result.expected))..'\n| '..mw.text.nowiki(tostring(result.actual))..'\n'
 else
 text=text..mw.text.nowiki(result.name)..'\n| '..' colspan="2" | '..mw.text.nowiki(result.message)..'\n'
 end
 else
 text=text..'| '..successIcon..'\n| '..mw.text.nowiki(result.name)..'\n|\n|\n'
 end
 end
 text=text..'|}\n'
 returntext
 end

 returnScribuntoUnit

AltStyle によって変換されたページ (->オリジナル) /