SUnit.st 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. Smalltalk current createPackage: 'SUnit' properties: #{}!
  2. Object subclass: #ResultAnnouncement
  3. instanceVariableNames: 'result'
  4. package: 'SUnit'!
  5. !ResultAnnouncement methodsFor: 'accessing'!
  6. result
  7. ^result
  8. !
  9. result: aTestResult
  10. result := aTestResult
  11. ! !
  12. Object subclass: #RunningTestContext
  13. instanceVariableNames: 'finished testCase result step'
  14. package: 'SUnit'!
  15. !RunningTestContext methodsFor: 'accessing'!
  16. finished: aBlock
  17. finished := aBlock
  18. !
  19. result: aTestResult
  20. result := aTestResult
  21. !
  22. testCase: aTestCase
  23. testCase := aTestCase
  24. ! !
  25. !RunningTestContext methodsFor: 'private'!
  26. exception: anException ifNotAsync: aBlock
  27. testCase isAsync
  28. ifTrue: [ step := [ testCase finished. anException signal ]]
  29. ifFalse: [ aBlock value ]
  30. ! !
  31. !RunningTestContext methodsFor: 'running'!
  32. execute: aBlock
  33. step := aBlock.
  34. [ step isNil ] whileFalse: [
  35. testCase context: self.
  36. [[[ step
  37. ensure: [ testCase context: nil. step := nil. testCase isAsync ifFalse: [ testCase tearDown ]]]
  38. on: TestFailure do: [:ex | self exception: ex ifNotAsync: [ result addFailure: testCase]]]
  39. on: Error do: [:ex | self exception: ex ifNotAsync: [ result addError: testCase]]]
  40. ensure: [ testCase isAsync ifFalse: [ result increaseRuns. finished value ]]]
  41. !
  42. start
  43. self execute: [ testCase setUp. testCase performTest ]
  44. ! !
  45. !RunningTestContext class methodsFor: 'instance creation'!
  46. testCase: aTestCase result: aTestResult finished: aBlock
  47. ^self new
  48. testCase: aTestCase;
  49. result: aTestResult;
  50. finished: aBlock;
  51. yourself
  52. ! !
  53. RunningTestContext subclass: #ErroringTestContext
  54. instanceVariableNames: ''
  55. package: 'SUnit'!
  56. !ErroringTestContext methodsFor: 'private'!
  57. exception: anException ifNotAsync: aBlock
  58. anException signal
  59. ! !
  60. !ErroringTestContext class methodsFor: 'instance creation'!
  61. testCase: aTestCase
  62. ^self
  63. testCase: aTestCase
  64. result: TestResult new
  65. finished: []
  66. ! !
  67. Object subclass: #TestCase
  68. instanceVariableNames: 'testSelector asyncTimeout context'
  69. package: 'SUnit'!
  70. !TestCase methodsFor: 'accessing'!
  71. context: aRunningTestContext
  72. context := aRunningTestContext
  73. !
  74. selector
  75. ^testSelector
  76. !
  77. setTestSelector: aSelector
  78. testSelector := aSelector
  79. ! !
  80. !TestCase methodsFor: 'async'!
  81. async: aBlock
  82. | c |
  83. self mustBeAsync: '#async'.
  84. c := context.
  85. ^[ self isAsync ifTrue: [ c execute: aBlock ]]
  86. !
  87. finished
  88. self mustBeAsync: '#finished'.
  89. asyncTimeout := nil
  90. !
  91. graceTime: millis
  92. asyncTimeout := true
  93. !
  94. isAsync
  95. ^asyncTimeout notNil
  96. !
  97. mustBeAsync: aString
  98. self isAsync ifFalse: [ self error: aString, ' used without prior #graceTime:' ]
  99. ! !
  100. !TestCase methodsFor: 'private'!
  101. signalFailure: aString
  102. TestFailure new
  103. messageText: aString;
  104. signal
  105. ! !
  106. !TestCase methodsFor: 'running'!
  107. performTest
  108. asyncTimeout := nil.
  109. self perform: self selector
  110. !
  111. runCase
  112. "Runs a test case in isolated context, leaking all errors."
  113. (ErroringTestContext testCase: self) start
  114. !
  115. setUp
  116. !
  117. tearDown
  118. ! !
  119. !TestCase methodsFor: 'testing'!
  120. assert: aBoolean
  121. self assert: aBoolean description: 'Assertion failed'
  122. !
  123. assert: aBoolean description: aString
  124. aBoolean ifFalse: [self signalFailure: aString]
  125. !
  126. assert: expected equals: actual
  127. ^ self assert: (expected = actual) description: 'Expected: ', expected asString, ' but was: ', actual asString
  128. !
  129. deny: aBoolean
  130. self assert: aBoolean not
  131. !
  132. should: aBlock
  133. self assert: aBlock value
  134. !
  135. should: aBlock raise: anExceptionClass
  136. self assert: ([aBlock value. false]
  137. on: anExceptionClass
  138. do: [:ex | true])
  139. !
  140. shouldnt: aBlock raise: anExceptionClass
  141. self assert: ([aBlock value. true]
  142. on: anExceptionClass
  143. do: [:ex | false])
  144. ! !
  145. !TestCase class methodsFor: 'accessing'!
  146. allTestSelectors
  147. | selectors |
  148. selectors := self testSelectors.
  149. self shouldInheritSelectors ifTrue: [
  150. selectors addAll: self superclass allTestSelectors].
  151. ^selectors
  152. !
  153. buildSuite
  154. ^self allTestSelectors collect: [:each | self selector: each]
  155. !
  156. lookupHierarchyRoot
  157. ^TestCase
  158. !
  159. selector: aSelector
  160. ^self new
  161. setTestSelector: aSelector;
  162. yourself
  163. !
  164. testSelectors
  165. ^self methodDictionary keys select: [:each | each match: '^test']
  166. ! !
  167. !TestCase class methodsFor: 'testing'!
  168. isAbstract
  169. ^ self name = 'TestCase'
  170. !
  171. shouldInheritSelectors
  172. ^self ~= self lookupHierarchyRoot
  173. ! !
  174. Error subclass: #TestFailure
  175. instanceVariableNames: ''
  176. package: 'SUnit'!
  177. Object subclass: #TestResult
  178. instanceVariableNames: 'timestamp runs errors failures total'
  179. package: 'SUnit'!
  180. !TestResult methodsFor: 'accessing'!
  181. addError: anError
  182. self errors add: anError
  183. !
  184. addFailure: aFailure
  185. self failures add: aFailure
  186. !
  187. errors
  188. ^errors
  189. !
  190. failures
  191. ^failures
  192. !
  193. increaseRuns
  194. runs := runs + 1
  195. !
  196. runs
  197. ^runs
  198. !
  199. status
  200. ^self errors isEmpty
  201. ifTrue: [
  202. self failures isEmpty
  203. ifTrue: ['success']
  204. ifFalse: ['failure']]
  205. ifFalse: ['error']
  206. !
  207. timestamp
  208. ^timestamp
  209. !
  210. total
  211. ^total
  212. !
  213. total: aNumber
  214. total := aNumber
  215. ! !
  216. !TestResult methodsFor: 'initialization'!
  217. initialize
  218. super initialize.
  219. timestamp := Date now.
  220. runs := 0.
  221. errors := Array new.
  222. failures := Array new.
  223. total := 0
  224. ! !
  225. Object subclass: #TestSuiteRunner
  226. instanceVariableNames: 'suite result announcer runNextTest'
  227. package: 'SUnit'!
  228. !TestSuiteRunner methodsFor: 'accessing'!
  229. announcer
  230. ^announcer
  231. !
  232. result
  233. ^result
  234. !
  235. suite: aCollection
  236. suite := aCollection
  237. ! !
  238. !TestSuiteRunner methodsFor: 'actions'!
  239. resume
  240. runNextTest fork.
  241. announcer announce: (ResultAnnouncement new result: result)
  242. !
  243. run
  244. result total: suite size.
  245. self resume
  246. ! !
  247. !TestSuiteRunner methodsFor: 'initialization'!
  248. initialize
  249. super initialize.
  250. announcer := Announcer new.
  251. result := TestResult new.
  252. runNextTest := [ | runs | runs := result runs. runs < result total ifTrue: [ (self contextOf: runs + 1) start ]].
  253. ! !
  254. !TestSuiteRunner methodsFor: 'private'!
  255. contextOf: anInteger
  256. ^RunningTestContext testCase: (suite at: anInteger) result: result finished: [ self resume ]
  257. ! !
  258. !TestSuiteRunner class methodsFor: 'instance creation'!
  259. new
  260. self shouldNotImplement
  261. !
  262. on: aCollection
  263. ^super new suite: aCollection
  264. ! !