SUnit.st 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. Object subclass: #TestCase
  2. instanceVariableNames: 'testedClass'
  3. category: 'SUnit'!
  4. !TestCase methodsFor: 'accessing'!
  5. testedClass
  6. ^testedClass
  7. !
  8. testedClass: aClass
  9. testedClass := aClass
  10. ! !
  11. !TestCase methodsFor: 'private'!
  12. cleanUpInstanceVariables
  13. self class instanceVariableNames do: [ :name |
  14. name = 'testSelector' ifFalse: [
  15. self instVarAt: name put: nil ]]
  16. !
  17. signalFailure: aString
  18. TestFailure new
  19. messageText: aString;
  20. signal
  21. ! !
  22. !TestCase methodsFor: 'running'!
  23. setUp
  24. !
  25. tearDown
  26. !
  27. methods
  28. ^self class methodDictionary keys select: [:each | each match: '^test']
  29. !
  30. runCaseFor: aTestResult
  31. [self setUp.
  32. self performTestFor: aTestResult]
  33. on: Error
  34. do: [:ex |
  35. self tearDown.
  36. self cleanUpInstanceVariables.
  37. ex signal].
  38. self tearDown.
  39. self cleanUpInstanceVariables
  40. !
  41. performTestFor: aResult
  42. self methods do: [:each |
  43. [[self perform: each]
  44. on: TestFailure do: [:ex | aResult addFailure: self class name, '>>', each]]
  45. on: Error do: [:ex | aResult addError: self class name, '>>', each].
  46. aResult increaseRuns]
  47. ! !
  48. !TestCase methodsFor: 'testing'!
  49. assert: aBoolean
  50. aBoolean ifFalse: [self signalFailure: 'Assertion failed']
  51. !
  52. deny: aBoolean
  53. self assert: aBoolean not
  54. !
  55. assert: expected equals: actual
  56. ^ self assert: (expected = actual)
  57. ! !
  58. TestCase subclass: #ExampleTest
  59. instanceVariableNames: 'test'
  60. category: 'SUnit'!
  61. !ExampleTest methodsFor: 'not yet classified'!
  62. testFailure
  63. self deny: true
  64. !
  65. testPasses
  66. 100000 timesRepeat: [self assert: 1 + 1 = 2]
  67. !
  68. testError
  69. self assert: 1 foo
  70. ! !
  71. TabWidget subclass: #ProgressBar
  72. instanceVariableNames: 'percent progressDiv div'
  73. category: 'SUnit'!
  74. !ProgressBar methodsFor: 'accessing'!
  75. percent
  76. ^percent ifNil: [0]
  77. !
  78. percent: aNumber
  79. percent := aNumber
  80. ! !
  81. !ProgressBar methodsFor: 'rendering'!
  82. renderOn: html
  83. div := html div
  84. class: 'progress_bar';
  85. yourself.
  86. self renderProgressBar
  87. !
  88. renderProgressBar
  89. div contents: [:html |
  90. html div
  91. class: 'progress';
  92. style: 'width:', self percent asString, '%']
  93. ! !
  94. !ProgressBar methodsFor: 'updating'!
  95. updatePercent: aNumber
  96. self percent: aNumber.
  97. self renderProgressBar
  98. ! !
  99. Error subclass: #TestFailure
  100. instanceVariableNames: ''
  101. category: 'SUnit'!
  102. TabWidget subclass: #TestRunner
  103. instanceVariableNames: 'selectedCategories categoriesList selectedClasses classesList selectedMethods progressBar methodsList result statusDiv'
  104. category: 'SUnit'!
  105. !TestRunner methodsFor: 'accessing'!
  106. label
  107. ^'[Test runner]'
  108. !
  109. categories
  110. | categories |
  111. categories := Array new.
  112. self allClasses do: [:each |
  113. (categories includes: each category) ifFalse: [
  114. categories add: each category]].
  115. ^categories sort
  116. !
  117. classes
  118. ^(self allClasses
  119. select: [:each | self selectedCategories includes: each category])
  120. sort: [:a :b | a name > b name]
  121. !
  122. selectedCategories
  123. ^selectedCategories ifNil: [selectedCategories := Array new]
  124. !
  125. allClasses
  126. ^TestCase allSubclasses
  127. !
  128. selectedClasses
  129. ^selectedClasses ifNil: [selectedClasses := Array new]
  130. !
  131. progressBar
  132. ^progressBar ifNil: [progressBar := ProgressBar new]
  133. !
  134. selectedMethods
  135. ^selectedMethods ifNil: [self selectedClasses collect: [:each |
  136. each methodDictionary keys select: [:key | key beginsWith: 'test' ]]]
  137. !
  138. statusInfo
  139. ^self printTotal, self printPasses, self printErrors, self printFailures
  140. !
  141. result
  142. ^result
  143. !
  144. failedMethods
  145. self result failures collect: [:each |
  146. html li
  147. class: 'failures';
  148. with: each]
  149. ! !
  150. !TestRunner methodsFor: 'actions'!
  151. selectAllCategories
  152. self categories do: [:each |
  153. (selectedCategories includes: each) ifFalse: [
  154. self selectedCategories add: each]].
  155. self
  156. updateCategoriesList;
  157. updateClassesList
  158. !
  159. toggleCategory: aCategory
  160. (self isSelectedCategory: aCategory)
  161. ifFalse: [selectedCategories add: aCategory]
  162. ifTrue: [selectedCategories remove: aCategory].
  163. self
  164. updateCategoriesList;
  165. updateClassesList
  166. !
  167. toggleClass: aClass
  168. (self isSelectedClass: aClass)
  169. ifFalse: [selectedClasses add: aClass]
  170. ifTrue: [selectedClasses remove: aClass].
  171. self
  172. updateClassesList
  173. !
  174. selectAllClasses
  175. self classes do: [:each |
  176. (selectedClasses includes: each) ifFalse: [
  177. self selectedClasses add: each]].
  178. self
  179. updateCategoriesList;
  180. updateClassesList
  181. !
  182. run: aCollection
  183. result := TestResult new.
  184. self
  185. updateStatusDiv;
  186. updateMethodsList.
  187. self progressBar updatePercent: 0.
  188. result total: (aCollection inject: 0 into: [:acc :each | acc + each methods size]).
  189. aCollection do: [:each |
  190. [each runCaseFor: result.
  191. self progressBar updatePercent: result runs / result total * 100.
  192. self updateStatusDiv.
  193. self updateMethodsList] valueWithTimeout: 100].
  194. ! !
  195. !TestRunner methodsFor: 'initialization'!
  196. initialize
  197. super initialize.
  198. result := TestResult new
  199. ! !
  200. !TestRunner methodsFor: 'printing'!
  201. printErrors
  202. ^self result errors size asString , ' errors, '
  203. !
  204. printFailures
  205. ^self result failures size asString, ' failures'
  206. !
  207. printPasses
  208. ^(((self result total) - (self result errors size + (self result failures size))) asString) , ' passes, '
  209. !
  210. printTotal
  211. ^self result total asString, ' runs, '
  212. ! !
  213. !TestRunner methodsFor: 'rendering'!
  214. renderBoxOn: html
  215. self
  216. renderCategoriesOn: html;
  217. renderClassesOn: html;
  218. renderResultsOn: html
  219. !
  220. renderButtonsOn: html
  221. html button
  222. with: 'Run selected';
  223. onClick: [self run: (self selectedClasses collect: [:each | each new])]
  224. !
  225. renderCategoriesOn: html
  226. categoriesList := html ul class: 'jt_column sunit categories'.
  227. self updateCategoriesList
  228. !
  229. renderClassesOn: html
  230. classesList := html ul class: 'jt_column sunit classes'.
  231. self updateClassesList
  232. !
  233. renderResultsOn: html
  234. statusDiv := html div.
  235. html with: self progressBar.
  236. methodsList := html ul class: 'jt_column sunit methods'.
  237. self updateMethodsList.
  238. self updateStatusDiv
  239. !
  240. renderFailuresOn: html
  241. self result failures do: [:each |
  242. html li
  243. class: 'failures';
  244. with: each]
  245. !
  246. renderErrorsOn: html
  247. self result errors do: [:each |
  248. html li
  249. class: 'errors';
  250. with: each]
  251. ! !
  252. !TestRunner methodsFor: 'testing'!
  253. canBeClosed
  254. ^true
  255. !
  256. isSelectedClass: aClass
  257. ^(self selectedClasses includes: aClass)
  258. !
  259. isSelectedCategory: aCategory
  260. ^(self selectedCategories includes: aCategory)
  261. ! !
  262. !TestRunner methodsFor: 'updating'!
  263. updateCategoriesList
  264. categoriesList contents: [:html |
  265. html li
  266. class: 'all';
  267. with: 'All';
  268. onClick: [self selectAllCategories].
  269. self categories do: [:each || li |
  270. li := html li.
  271. (self selectedCategories includes: each) ifTrue: [
  272. li class: 'selected'].
  273. li
  274. with: each;
  275. onClick: [self toggleCategory: each]]]
  276. !
  277. updateClassesList
  278. classesList contents: [:html |
  279. (self selectedCategories isEmpty) ifFalse: [
  280. html li
  281. class: 'all';
  282. with: 'All';
  283. onClick: [self selectAllClasses]].
  284. self classes do: [:each || li |
  285. li := html li.
  286. (self selectedClasses includes: each) ifTrue: [
  287. li class: 'selected'].
  288. li
  289. with: each name;
  290. onClick: [self toggleClass: each]]]
  291. !
  292. updateMethodsList
  293. methodsList contents: [:html |
  294. self renderFailuresOn: html.
  295. self renderErrorsOn: html]
  296. !
  297. updateStatusDiv
  298. statusDiv class: 'sunit status ', result status.
  299. statusDiv contents: [:html |
  300. html span with: self statusInfo]
  301. ! !
  302. Object subclass: #TestResult
  303. instanceVariableNames: 'timestamp runs errors failures total'
  304. category: 'SUnit'!
  305. !TestResult methodsFor: 'accessing'!
  306. timestamp
  307. ^timestamp
  308. !
  309. errors
  310. ^errors
  311. !
  312. failures
  313. ^failures
  314. !
  315. total
  316. ^total
  317. !
  318. total: aNumber
  319. total := aNumber
  320. !
  321. addError: anError
  322. self errors add: anError
  323. !
  324. addFailure: aFailure
  325. self failures add: aFailure
  326. !
  327. runs
  328. ^runs
  329. !
  330. increaseRuns
  331. runs := runs + 1
  332. !
  333. status
  334. ^self errors isEmpty
  335. ifTrue: [
  336. self failures isEmpty
  337. ifTrue: ['success']
  338. ifFalse: ['failure']]
  339. ifFalse: ['error']
  340. ! !
  341. !TestResult methodsFor: 'initialization'!
  342. initialize
  343. super initialize.
  344. timestamp := Date now.
  345. runs := 0.
  346. errors := Array new.
  347. failures := Array new.
  348. total := 0
  349. ! !
  350. TestCase subclass: #ExampleTest2
  351. instanceVariableNames: ''
  352. category: 'SUnit'!
  353. !ExampleTest2 methodsFor: 'not yet classified'!
  354. testPasses
  355. 100000 timesRepeat: [self assert: 1 + 1 = 2]
  356. ! !
  357. TestCase subclass: #ExampleTest3
  358. instanceVariableNames: ''
  359. category: 'SUnit'!
  360. !ExampleTest3 methodsFor: 'not yet classified'!
  361. testPasses
  362. 100000 timesRepeat: [self assert: 1 + 1 = 2]
  363. ! !