SUnit.st 8.2 KB

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