SUnit.st 6.5 KB

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