SUnit.st 6.2 KB

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