Chris Muller uploaded a new version of SUnit to project Squeak 4.6:
http://source.squeak.org/squeak46/SUnit-mt.102.mcz ==================== Summary ==================== Name: SUnit-mt.102 Author: mt Time: 19 April 2015, 7:24:35.203 am UUID: 3e115dcf-b404-3043-814e-ecb6f43f9192 Ancestors: SUnit-bf.101 Extracted logic of being a test method to be easier reusable in extensions and tools. Moved test-class-check from SUnitTools to here. ==================== Snapshot ==================== SystemOrganization addCategory: #'SUnit-Extensions'! SystemOrganization addCategory: #'SUnit-Kernel'! SystemOrganization addCategory: #'SUnit-Tests'! ----- Method: CompiledMethod>>isTestMethod (in category '*SUnit-testing') ----- isTestMethod ^ self methodClass isTestClass and: [self selector isTestSelector]! Exception subclass: #TestFailure instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'SUnit-Kernel'! !TestFailure commentStamp: '<historical>' prior: 0! Signaled in case of a failed test (failure). The test framework distinguishes between failures and errors. A failure is anticipated and checked for with assertions. Errors are unanticipated problems like a division by 0 or an index out of bounds ...! TestFailure subclass: #ResumableTestFailure instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'SUnit-Kernel'! !ResumableTestFailure commentStamp: '<historical>' prior: 0! A ResumableTestFailure triggers a TestFailure, but lets execution of the TestCase continue. this is useful when iterating through collections, and #assert: ing on each element. in combination with methods like testcase>>#assert:description:, this lets you run through a whole collection and note which tests pass. here''s an example: (1 to: 30) do: [ :each | self assert: each odd description: each printString, ' is even' resumable: true] for each element where #odd returns <false>, the element will be printed to the Transcript. ! ----- Method: ResumableTestFailure>>isResumable (in category 'camp smalltalk') ----- isResumable "Of course a ResumableTestFailure is resumable ;-)" ^true! ----- Method: ResumableTestFailure>>sunitExitWith: (in category 'camp smalltalk') ----- sunitExitWith: aValue self resume: aValue! ----- Method: TestFailure>>defaultAction (in category 'camp smalltalk') ----- defaultAction Processor activeProcess debug: self signalerContext title: self description! ----- Method: TestFailure>>isResumable (in category 'camp smalltalk') ----- isResumable ^ false! ----- Method: MethodReference>>isTestMethod (in category '*SUnit-testing') ----- isTestMethod ^ self compiledMethod isTestMethod! ----- Method: Symbol>>isTestSelector (in category '*SUnit-testing') ----- isTestSelector ^ self beginsWith: 'test'! Object subclass: #ClassFactoryForTestCase instanceVariableNames: 'createdClasses' classVariableNames: '' poolDictionaries: '' category: 'SUnit-Extensions'! ----- Method: ClassFactoryForTestCase>>cleanUp (in category 'cleaning') ----- cleanUp | createdClassNames | createdClassNames := self createdClassNames. self deleteClasses. self deletePackage. self cleanUpChangeSetForClassNames: createdClassNames. self createdClasses: IdentitySet new! ----- Method: ClassFactoryForTestCase>>cleanUpChangeSetForClassNames: (in category 'cleaning') ----- cleanUpChangeSetForClassNames: classeNames | changeSet | changeSet := ChangeSet current. classeNames do: [:name| changeSet removeClassChanges: name; removeClassChanges: name, ' class']. ! ----- Method: ClassFactoryForTestCase>>createdClassNames (in category 'accessing') ----- createdClassNames ^self createdClasses collect: [:class| class name]! ----- Method: ClassFactoryForTestCase>>createdClasses (in category 'accessing') ----- createdClasses ^createdClasses! ----- Method: ClassFactoryForTestCase>>createdClasses: (in category 'accessing') ----- createdClasses: classes createdClasses := classes asIdentitySet ! ----- Method: ClassFactoryForTestCase>>defaultCategory (in category 'accessing') ----- defaultCategory ^ (self packageName , '-', self defaultCategoryPostfix) asSymbol! ----- Method: ClassFactoryForTestCase>>defaultCategoryPostfix (in category 'accessing') ----- defaultCategoryPostfix ^ #Default! ----- Method: ClassFactoryForTestCase>>delete: (in category 'cleaning') ----- delete: aClass aClass isObsolete ifTrue: [^self]. aClass removeFromChanges. aClass removeFromSystemUnlogged ! ----- Method: ClassFactoryForTestCase>>deleteClasses (in category 'cleaning') ----- deleteClasses self createdClasses do: [:class| self delete: class]! ----- Method: ClassFactoryForTestCase>>deletePackage (in category 'cleaning') ----- deletePackage | categoriesMatchString | categoriesMatchString := self packageName, '-*'. SystemOrganization removeCategoriesMatching: categoriesMatchString! ----- Method: ClassFactoryForTestCase>>initialize (in category 'cleaning') ----- initialize super initialize. self createdClasses: IdentitySet new! ----- Method: ClassFactoryForTestCase>>newClass (in category 'creating') ----- newClass ^self newSubclassOf: Object instanceVariableNames: '' classVariableNames: ''! ----- Method: ClassFactoryForTestCase>>newClassInCategory: (in category 'creating') ----- newClassInCategory: category ^self newSubclassOf: Object instanceVariableNames: '' classVariableNames: '' category: category! ----- Method: ClassFactoryForTestCase>>newName (in category 'creating') ----- newName | postFix | postFix := (self createdClasses size + 1) printString. ^#ClassForTestToBeDeleted, postFix! ----- Method: ClassFactoryForTestCase>>newSubclassOf:instanceVariableNames:classVariableNames: (in category 'creating') ----- newSubclassOf: aClass instanceVariableNames: ivNamesString classVariableNames: classVarsString ^self newSubclassOf: aClass instanceVariableNames: ivNamesString classVariableNames: classVarsString category: self defaultCategoryPostfix! ----- Method: ClassFactoryForTestCase>>newSubclassOf:instanceVariableNames:classVariableNames:category: (in category 'creating') ----- newSubclassOf: aClass instanceVariableNames: ivNamesString classVariableNames: classVarsString category: category | newClass | newClass := aClass subclass: self newName asSymbol instanceVariableNames: ivNamesString classVariableNames: classVarsString poolDictionaries: '' category: (self packageName, '-', category) asSymbol. self createdClasses add: newClass. ^newClass! ----- Method: ClassFactoryForTestCase>>packageName (in category 'accessing') ----- packageName ^#CategoryForTestToBeDeleted! ----- Method: Object>>isTestClass (in category '*SUnit-testing') ----- isTestClass ^ false! Object subclass: #TestCase instanceVariableNames: 'testSelector timeout' classVariableNames: '' poolDictionaries: '' category: 'SUnit-Kernel'! TestCase class instanceVariableNames: 'history'! !TestCase commentStamp: '<historical>' prior: 0! A TestCase is a Command representing the future running of a test case. Create one with the class method #selector: aSymbol, passing the name of the method to be run when the test case runs. When you discover a new fixture, subclass TestCase, declare instance variables for the objects in the fixture, override #setUp to initialize the variables, and possibly override# tearDown to deallocate any external resources allocated in #setUp. When you are writing a test case method, send #assert: aBoolean when you want to check for an expected value. For example, you might say "self assert: socket isOpen" to test whether or not a socket is open at a point in a test.! TestCase class instanceVariableNames: 'history'! TestCase subclass: #ClassFactoryForTestCaseTest instanceVariableNames: 'factory' classVariableNames: '' poolDictionaries: '' category: 'SUnit-Tests'! ----- Method: ClassFactoryForTestCaseTest class>>lastStoredRun (in category 'history') ----- lastStoredRun ^ ((Dictionary new) add: (#passed->((Set new) add: #testDefaultCategoryCleanUp; add: #testPackageCleanUp; add: #testSingleClassCreation; add: #testClassCreationInDifferentCategories; add: #testClassFastCreationInDifferentCategories; add: #testMultipleClassCreation; add: #testSingleClassFastCreation; yourself)); add: (#timeStamp->'22 November 2008 10:11:35 pm'); add: (#failures->((Set new))); add: (#errors->((Set new))); yourself)! ----- Method: ClassFactoryForTestCaseTest>>setUp (in category 'setUp-tearDown') ----- setUp super setUp. factory := ClassFactoryForTestCase new! ----- Method: ClassFactoryForTestCaseTest>>tearDown (in category 'setUp-tearDown') ----- tearDown super tearDown. factory cleanUp! ----- Method: ClassFactoryForTestCaseTest>>testClassCreationInDifferentCategories (in category 'testing') ----- testClassCreationInDifferentCategories | firstThreeClasses lastTwoClasses | 3 timesRepeat: [ factory newSubclassOf: Object instanceVariableNames: '' classVariableNames: '' category: #One]. firstThreeClasses := factory createdClasses copy. 2 timesRepeat: [ factory newSubclassOf: Object instanceVariableNames: '' classVariableNames: '' category: #Two]. lastTwoClasses := factory createdClasses copyWithoutAll: firstThreeClasses. self assert: (firstThreeClasses allSatisfy: [:class| class category = (factory packageName, '-', #One) asSymbol]). self assert: (lastTwoClasses allSatisfy: [:class| class category = (factory packageName, '-', #Two) asSymbol]).! ----- Method: ClassFactoryForTestCaseTest>>testClassFastCreationInDifferentCategories (in category 'testing') ----- testClassFastCreationInDifferentCategories | firstThreeClasses lastTwoClasses | 3 timesRepeat: [ factory newClassInCategory: #One]. firstThreeClasses := factory createdClasses copy. 2 timesRepeat: [ factory newClassInCategory: #Two]. lastTwoClasses := factory createdClasses copyWithoutAll: firstThreeClasses. self assert: (firstThreeClasses allSatisfy: [:class| class category = (factory packageName, '-', #One) asSymbol]). self assert: (lastTwoClasses allSatisfy: [:class| class category = (factory packageName, '-', #Two) asSymbol]).! ----- Method: ClassFactoryForTestCaseTest>>testDefaultCategoryCleanUp (in category 'testing') ----- testDefaultCategoryCleanUp | createdClassNames allClasses | 3 timesRepeat: [ factory newClass]. createdClassNames := factory createdClassNames. factory cleanUp. self assert: (factory createdClasses allSatisfy: [:class| class isObsolete]). allClasses := SystemNavigation new allClasses. self assert: (factory createdClasses noneSatisfy: [:class| allClasses includes: class]). self deny: (SystemOrganization categories includes: factory defaultCategory). self deny: (ChangeSet current changedClassNames includesAnyOf: createdClassNames) ! ----- Method: ClassFactoryForTestCaseTest>>testMultipleClassCreation (in category 'testing') ----- testMultipleClassCreation 5 timesRepeat: [ factory newClass]. self assert: (SystemNavigation new allClasses includesAllOf: factory createdClasses). self assert: factory createdClassNames asSet size = 5. self assert: (SystemOrganization listAtCategoryNamed: factory defaultCategory) asSet = factory createdClassNames asSet! ----- Method: ClassFactoryForTestCaseTest>>testPackageCleanUp (in category 'testing') ----- testPackageCleanUp | createdClassNames allClasses | 3 timesRepeat: [ factory newClassInCategory: #One]. 2 timesRepeat: [ factory newClassInCategory: #Two]. createdClassNames := factory createdClassNames. factory cleanUp. self assert: (factory createdClasses allSatisfy: [:class| class isObsolete]). allClasses := SystemNavigation new allClasses. self assert: (factory createdClasses noneSatisfy: [:class| allClasses includes: class]). self assert: (SystemOrganization categoriesMatching: factory packageName, '*') isEmpty. self deny: (ChangeSet current changedClassNames includesAnyOf: createdClassNames) ! ----- Method: ClassFactoryForTestCaseTest>>testSingleClassCreation (in category 'testing') ----- testSingleClassCreation |class elementsInCategoryForTest | class := factory newSubclassOf: Object instanceVariableNames: 'a b c' classVariableNames: 'X Y'. self assert: (SystemNavigation new allClasses includes: class). elementsInCategoryForTest := SystemOrganization listAtCategoryNamed: factory defaultCategory. self assert: elementsInCategoryForTest = {class name}. self assert: class instVarNames = #(a b c). self assert: class classPool keys asSet = #(X Y) asSet! ----- Method: ClassFactoryForTestCaseTest>>testSingleClassFastCreation (in category 'testing') ----- testSingleClassFastCreation |class elementsInCategoryForTest | class := factory newClass. self assert: (SystemNavigation new allClasses includes: class). elementsInCategoryForTest := SystemOrganization listAtCategoryNamed: factory defaultCategory. self assert: elementsInCategoryForTest = {class name}. self assert: class instVarNames isEmpty. self assert: class classPool isEmpty! TestCase subclass: #ClassTestCase instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'SUnit-Extensions'! !ClassTestCase commentStamp: 'brp 7/26/2003 16:57' prior: 0! This class is intended for unit tests of individual classes and their metaclasses. It provides methods to determine the coverage of the unit tests. Subclasses are expected to re-implement #classesToBeTested and #selectorsToBeIgnored. They should also implement to confirm that all methods have been tested. #testCoverage super testCoverage. ! ----- Method: ClassTestCase class>>isAbstract (in category 'Testing') ----- isAbstract "Override to true if a TestCase subclass is Abstract and should not have TestCase instances built from it" ^self name = #ClassTestCase ! ----- Method: ClassTestCase class>>mustTestCoverage (in category 'Testing') ----- mustTestCoverage ^ false! ----- Method: ClassTestCase>>categoriesForClass: (in category 'private') ----- categoriesForClass: aClass ^ aClass organization allMethodSelectors collect: [:each | aClass organization categoryOfElement: each]. ! ----- Method: ClassTestCase>>classToBeTested (in category 'coverage') ----- classToBeTested self subclassResponsibility! ----- Method: ClassTestCase>>selectorsNotTested (in category 'coverage') ----- selectorsNotTested ^ self selectorsToBeTested difference: self selectorsTested. ! ----- Method: ClassTestCase>>selectorsTested (in category 'Coverage') ----- selectorsTested | literals | literals := Set new. self class selectorsAndMethodsDo: [ :s :m | (s beginsWith: 'test') ifTrue: [ literals addAll: (m messages)] ]. ^ literals asSortedArray! ----- Method: ClassTestCase>>selectorsToBeIgnored (in category 'coverage') ----- selectorsToBeIgnored ^ #(#DoIt #DoItIn:)! ----- Method: ClassTestCase>>selectorsToBeTested (in category 'coverage') ----- selectorsToBeTested ^ ( { self classToBeTested. self classToBeTested class } gather: [:c | c selectors]) difference: self selectorsToBeIgnored! ----- Method: ClassTestCase>>targetClass (in category 'private') ----- targetClass |className| className := self class name asText copyFrom: 0 to: self class name size - 4. ^ Smalltalk at: (className asString asSymbol). ! ----- Method: ClassTestCase>>testClassComment (in category 'tests') ----- testClassComment self shouldnt: [self targetClass organization hasNoComment].! ----- Method: ClassTestCase>>testCoverage (in category 'tests') ----- testCoverage | untested | self class mustTestCoverage ifTrue: [ untested := self selectorsNotTested. self assert: untested isEmpty description: untested size asString, ' selectors are not covered' ]! ----- Method: ClassTestCase>>testNew (in category 'tests') ----- testNew "This should not throw an exception." self targetClass new.! ----- Method: ClassTestCase>>testUnCategorizedMethods (in category 'tests') ----- testUnCategorizedMethods | categories slips uncategorisedMethods | categories := self categoriesForClass: self targetClass. slips := categories select: [:each | each = #'as yet unclassified']. uncategorisedMethods := self targetClass organization listAtCategoryNamed: #'as yet unclassified'. self assert: slips isEmpty description: ('{1} has uncategorised methods: {2}' format: {self targetClass. (uncategorisedMethods collect: #printString) asCommaString}).! TestCase subclass: #LongTestCase instanceVariableNames: '' classVariableNames: 'ShouldRun' poolDictionaries: '' category: 'SUnit-Extensions'! !LongTestCase commentStamp: 'ul 12/15/2009 13:06' prior: 0! A LongTestCase is a TestCase that usually takes a long time to run. Because of this users can decide if they want to execute these or not, by changing the "Run long test cases" preference.! ----- Method: LongTestCase class>>allTestSelectors (in category 'accessing') ----- allTestSelectors self shouldRun ifTrue: [ ^super testSelectors ]. ^#().! ----- Method: LongTestCase class>>buildSuite (in category 'instance creation') ----- buildSuite self shouldRun ifTrue: [ ^super buildSuite ]. ^self suiteClass new! ----- Method: LongTestCase class>>doNotRunLongTestCases (in category 'accessing') ----- doNotRunLongTestCases self shouldRun: false! ----- Method: LongTestCase class>>isAbstract (in category 'testing') ----- isAbstract "Override to true if a TestCase subclass is Abstract and should not have TestCase instances built from it" ^self name == #LongTestCase ! ----- Method: LongTestCase class>>runLongTestCases (in category 'accessing') ----- runLongTestCases self shouldRun: true! ----- Method: LongTestCase class>>shouldRun (in category 'accessing') ----- shouldRun <preference: 'Run long test cases' category: 'SUnit' description: 'If true, the tests defined in subclasses of LongTestCase will run, if they are selected in the Test Runner, otherwise not. As the name suggests, running these tests can take a long time.' type: #Boolean> ^ShouldRun ifNil: [ true ]! ----- Method: LongTestCase class>>shouldRun: (in category 'accessing') ----- shouldRun: aBoolean ShouldRun := aBoolean! ----- Method: LongTestCase>>defaultTimeout (in category 'as yet unclassified') ----- defaultTimeout "Answer the default timeout to use for tests in this test case. The timeout is a value in seconds." ^super defaultTimeout * 10! LongTestCase subclass: #LongTestCaseTestUnderTest instanceVariableNames: '' classVariableNames: 'RunStatus' poolDictionaries: '' category: 'SUnit-Extensions'! ----- Method: LongTestCaseTestUnderTest class>>hasRun (in category 'accessing') ----- hasRun ^ RunStatus! ----- Method: LongTestCaseTestUnderTest class>>markAsNotRun (in category 'accessing') ----- markAsNotRun ^ RunStatus := false! ----- Method: LongTestCaseTestUnderTest>>testWhenRunMarkTestedToTrue (in category 'testing') ----- testWhenRunMarkTestedToTrue RunStatus := true.! TestCase subclass: #LongTestCaseTest instanceVariableNames: 'preferenceValue' classVariableNames: '' poolDictionaries: '' category: 'SUnit-Extensions'! ----- Method: LongTestCaseTest>>setUp (in category 'as yet unclassified') ----- setUp preferenceValue := LongTestCase shouldRun! ----- Method: LongTestCaseTest>>tearDown (in category 'as yet unclassified') ----- tearDown LongTestCase shouldRun: preferenceValue! ----- Method: LongTestCaseTest>>testLongTestCaseDoNotRun (in category 'testing') ----- testLongTestCaseDoNotRun "self debug: #testLongTestCaseDoNotRun" "self run: #testLongTestCaseDoNotRun" LongTestCase doNotRunLongTestCases. LongTestCaseTestUnderTest markAsNotRun. self deny: LongTestCaseTestUnderTest hasRun. LongTestCaseTestUnderTest suite run. self deny: LongTestCaseTestUnderTest hasRun. ! ----- Method: LongTestCaseTest>>testLongTestCaseRun (in category 'testing') ----- testLongTestCaseRun "self debug: #testLongTestCaseRun" "self run: #testLongTestCaseRun" LongTestCase runLongTestCases. LongTestCaseTestUnderTest markAsNotRun. self deny: LongTestCaseTestUnderTest hasRun. LongTestCaseTestUnderTest suite run. self assert: LongTestCaseTestUnderTest hasRun. LongTestCase doNotRunLongTestCases. ! TestCase subclass: #ResumableTestFailureTestCase instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'SUnit-Tests'! ----- Method: ResumableTestFailureTestCase class>>lastStoredRun (in category 'history') ----- lastStoredRun ^ ((Dictionary new) add: (#passed->((Set new) add: #testResumable; yourself)); add: (#timeStamp->'22 November 2008 10:11:35 pm'); add: (#failures->((Set new))); add: (#errors->((Set new))); yourself)! ----- Method: ResumableTestFailureTestCase>>errorTest (in category 'not categorized') ----- errorTest 1 zork ! ----- Method: ResumableTestFailureTestCase>>failureTest (in category 'not categorized') ----- failureTest self assert: false description: 'You should see me' resumable: true; assert: false description: 'You should see me too' resumable: true; assert: false description: 'You should see me last' resumable: false; assert: false description: 'You should not see me' resumable: true ! ----- Method: ResumableTestFailureTestCase>>okTest (in category 'not categorized') ----- okTest self assert: true ! ----- Method: ResumableTestFailureTestCase>>regularTestFailureTest (in category 'not categorized') ----- regularTestFailureTest self assert: false description: 'You should see me' ! ----- Method: ResumableTestFailureTestCase>>resumableTestFailureTest (in category 'not categorized') ----- resumableTestFailureTest self assert: false description: 'You should see me' resumable: true; assert: false description: 'You should see me too' resumable: true; assert: false description: 'You should see me last' resumable: false; assert: false description: 'You should not see me' resumable: true ! ----- Method: ResumableTestFailureTestCase>>testResumable (in category 'not categorized') ----- testResumable | result suite | suite := TestSuite new. suite addTest: (self class selector: #errorTest). suite addTest: (self class selector: #regularTestFailureTest). suite addTest: (self class selector: #resumableTestFailureTest). suite addTest: (self class selector: #okTest). result := suite run. self assert: result failures size = 2; assert: result errors size = 1 ! TestCase subclass: #SUnitExtensionsTest instanceVariableNames: 'stream' classVariableNames: '' poolDictionaries: '' category: 'SUnit-Tests'! ----- Method: SUnitExtensionsTest class>>lastStoredRun (in category 'history') ----- lastStoredRun ^ ((Dictionary new) add: (#passed->((Set new) add: #testNoExceptionWithMatchingString; add: #testNoExceptionWithNoMatchingString; add: #testExceptionWithMatchingString; add: #testExceptionWithoutMatchingString; add: #testValidShouldNotTakeMoreThan; add: #testInvalidShouldNotTakeMoreThanMilliseconds; add: #testDifferentExceptionInShouldRaiseWithExceptionDo; add: #testShouldRaiseWithExceptionDo; add: #testShouldFix; add: #testAssertionFailedInRaiseWithExceptionDo; add: #testAutoDenyFalse; add: #testAutoDenyTrue; add: #testAutoAssertFalse; add: #testAutoAssertTrue; add: #testValidShouldNotTakeMoreThanMilliseconds; add: #testErrorInRaiseWithExceptionDo; add: #testNoExceptionInShouldRaiseWithExceptionDo; add: #testInvalidShouldNotTakeMoreThan; yourself)); add: (#timeStamp->'22 November 2008 10:11:35 pm'); add: (#failures->((Set new))); add: (#errors->((Set new))); yourself)! ----- Method: SUnitExtensionsTest>>assertionFailedInRaiseWithExceptionDoTest (in category 'real tests') ----- assertionFailedInRaiseWithExceptionDoTest self should: [ Error signal ] raise: Error withExceptionDo: [ :anException | self assert: false ]! ----- Method: SUnitExtensionsTest>>differentExceptionInShouldRaiseWithExceptionDoTest (in category 'real tests') ----- differentExceptionInShouldRaiseWithExceptionDoTest [ self should: [ Error signal ] raise: Halt withExceptionDo: [ :anException | self assert: false description: 'should:raise:withExceptionDo: handled an exception that should not handle'] ] on: Error do: [ :anException | anException return: nil ]! ----- Method: SUnitExtensionsTest>>errorInRaiseWithExceptionDoTest (in category 'real tests') ----- errorInRaiseWithExceptionDoTest self should: [ Error signal ] raise: Error withExceptionDo: [ :anException | Error signal: 'A forced error' ]! ----- Method: SUnitExtensionsTest>>failureLog (in category 'test support') ----- failureLog ^self stream! ----- Method: SUnitExtensionsTest>>invalidShouldNotTakeMoreThan (in category 'real tests') ----- invalidShouldNotTakeMoreThan self should: [(Delay forMilliseconds: 100) wait] notTakeMoreThan: 50 milliSeconds.! ----- Method: SUnitExtensionsTest>>invalidShouldNotTakeMoreThanMilliseconds (in category 'real tests') ----- invalidShouldNotTakeMoreThanMilliseconds self should: [(Delay forMilliseconds: 100) wait] notTakeMoreThanMilliseconds: 50! ----- Method: SUnitExtensionsTest>>isLogging (in category 'testing') ----- isLogging ^true! ----- Method: SUnitExtensionsTest>>noExceptionInShouldRaiseWithExceptionDoTest (in category 'real tests') ----- noExceptionInShouldRaiseWithExceptionDoTest self should: [ ] raise: Error withExceptionDo: [ :anException | Error signal: 'Should not get here' ]! ----- Method: SUnitExtensionsTest>>shouldFixTest (in category 'real tests') ----- shouldFixTest self shouldFix: [ Error signal: 'any kind of error' ] ! ----- Method: SUnitExtensionsTest>>shouldRaiseWithExceptionDoTest (in category 'real tests') ----- shouldRaiseWithExceptionDoTest self should: [ Error signal: '1' ] raise: Error withExceptionDo: [ :anException | self assert: anException messageText = '1' ]! ----- Method: SUnitExtensionsTest>>shouldRaiseWithSignalDoTest (in category 'real tests') ----- shouldRaiseWithSignalDoTest self should: [ Error signal: '1' ] raise: Error withExceptionDo: [ :anException | self assert: anException messageText = '1' ]! ----- Method: SUnitExtensionsTest>>stream (in category 'accessing') ----- stream ^stream ifNil: [stream := WriteStream on: String new]! ----- Method: SUnitExtensionsTest>>testAssertionFailedInRaiseWithExceptionDo (in category 'test') ----- testAssertionFailedInRaiseWithExceptionDo | testCase testResult | testCase := self class selector: #assertionFailedInRaiseWithExceptionDoTest. testResult := testCase run. self assert: (testResult failures includes: testCase). self assert: testResult failures size=1. self assert: testResult passed isEmpty. self assert: testResult errors isEmpty. ! ----- Method: SUnitExtensionsTest>>testAutoAssertFalse (in category 'test') ----- testAutoAssertFalse | booleanCondition | self assert: self isLogging. self should: [ self assert: 1 = 2 description: 'self assert: 1 = 2' ] raise: TestResult failure. booleanCondition := (self stream contents subStrings: {Character cr}) last = 'self assert: 1 = 2'. self assert: booleanCondition! ----- Method: SUnitExtensionsTest>>testAutoAssertTrue (in category 'test') ----- testAutoAssertTrue self assert: 1 = 1. self assert: true! ----- Method: SUnitExtensionsTest>>testAutoDenyFalse (in category 'test') ----- testAutoDenyFalse | booleanCondition | self assert: self isLogging. self should: [ self deny: 1 = 1 description: 'self deny: 1 = 1'.] raise: TestResult failure. booleanCondition := (self stream contents subStrings: {Character cr}) last = 'self deny: 1 = 1'. self assert: booleanCondition! ----- Method: SUnitExtensionsTest>>testAutoDenyTrue (in category 'test') ----- testAutoDenyTrue self deny: 1 = 2. self deny: false! ----- Method: SUnitExtensionsTest>>testDifferentExceptionInShouldRaiseWithExceptionDo (in category 'test') ----- testDifferentExceptionInShouldRaiseWithExceptionDo | testCase testResult | testCase := self class selector: #differentExceptionInShouldRaiseWithExceptionDoTest. testResult := testCase run. self assert: (testResult passed includes: testCase). self assert: testResult errors isEmpty. self assert: testResult failures isEmpty. self assert: testResult passed size=1! ----- Method: SUnitExtensionsTest>>testErrorInRaiseWithExceptionDo (in category 'test') ----- testErrorInRaiseWithExceptionDo | testCase testResult | testCase := self class selector: #errorInRaiseWithExceptionDoTest. testResult := testCase run. self assert: (testResult errors includes: testCase). self assert: testResult errors size=1. self assert: testResult failures isEmpty. self assert: testResult passed isEmpty. ! ----- Method: SUnitExtensionsTest>>testExceptionWithMatchingString (in category 'as yet unclassified') ----- testExceptionWithMatchingString self should: [ Object obsolete ] raise: Error whoseDescriptionIncludes: 'NOT obsolete' description: 'tested obsoleting Object'! ----- Method: SUnitExtensionsTest>>testExceptionWithoutMatchingString (in category 'as yet unclassified') ----- testExceptionWithoutMatchingString self should: [ Object obsolete ] raise: Error whoseDescriptionDoesNotInclude: 'Zero' description: 'tested obsoleting Object'! ----- Method: SUnitExtensionsTest>>testInvalidShouldNotTakeMoreThan (in category 'test') ----- testInvalidShouldNotTakeMoreThan | testCase testResult | testCase := self class selector: #invalidShouldNotTakeMoreThan. testResult := testCase run. self assert: testResult passed isEmpty. self assert: testResult failures size = 1. self assert: (testResult failures includes: testCase). self assert: testResult errors isEmpty ! ----- Method: SUnitExtensionsTest>>testInvalidShouldNotTakeMoreThanMilliseconds (in category 'test') ----- testInvalidShouldNotTakeMoreThanMilliseconds | testCase testResult | testCase := self class selector: #invalidShouldNotTakeMoreThanMilliseconds. testResult := testCase run. self assert: testResult passed isEmpty. self assert: testResult failures size = 1. self assert: (testResult failures includes: testCase). self assert: testResult errors isEmpty ! ----- Method: SUnitExtensionsTest>>testNoExceptionInShouldRaiseWithExceptionDo (in category 'test') ----- testNoExceptionInShouldRaiseWithExceptionDo | testCase testResult | testCase := self class selector: #noExceptionInShouldRaiseWithExceptionDoTest. testResult := testCase run. self assert: (testResult failures includes: testCase). self assert: testResult failures size=1. self assert: testResult passed isEmpty. self assert: testResult errors isEmpty. ! ----- Method: SUnitExtensionsTest>>testNoExceptionWithMatchingString (in category 'as yet unclassified') ----- testNoExceptionWithMatchingString self shouldnt: [ Object obsolete ] raise: Error whoseDescriptionIncludes: 'Zero' description: 'tested obsoleting Object'! ----- Method: SUnitExtensionsTest>>testNoExceptionWithNoMatchingString (in category 'as yet unclassified') ----- testNoExceptionWithNoMatchingString self shouldnt: [ Object obsolete ] raise: Error whoseDescriptionDoesNotInclude: 'NOT' description: 'tested obsoleting Object'! ----- Method: SUnitExtensionsTest>>testShouldFix (in category 'test') ----- testShouldFix | testCase testResult | testCase := self class selector: #shouldFixTest. testResult := testCase run. self assert: (testResult passed includes: testCase). self assert: testResult passed size=1. self assert: testResult failures isEmpty. self assert: testResult errors isEmpty. ! ----- Method: SUnitExtensionsTest>>testShouldRaiseWithExceptionDo (in category 'test') ----- testShouldRaiseWithExceptionDo | testCase testResult | testCase := self class selector: #shouldRaiseWithExceptionDoTest. testResult := testCase run. self assert: (testResult passed includes: testCase). self assert: testResult passed size=1. self assert: testResult failures isEmpty. self assert: testResult errors isEmpty. ! ----- Method: SUnitExtensionsTest>>testValidShouldNotTakeMoreThan (in category 'test') ----- testValidShouldNotTakeMoreThan | testCase testResult | testCase := self class selector: #validShouldNotTakeMoreThan. testResult := testCase run. self assert: (testResult passed includes: testCase). self assert: testResult passed size = 1. self assert: testResult failures isEmpty. self assert: testResult errors isEmpty ! ----- Method: SUnitExtensionsTest>>testValidShouldNotTakeMoreThanMilliseconds (in category 'test') ----- testValidShouldNotTakeMoreThanMilliseconds | testCase testResult | testCase := self class selector: #validShouldNotTakeMoreThanMilliseconds. testResult := testCase run. self assert: (testResult passed includes: testCase). self assert: testResult passed size = 1. self assert: testResult failures isEmpty. self assert: testResult errors isEmpty ! ----- Method: SUnitExtensionsTest>>validShouldNotTakeMoreThan (in category 'real tests') ----- validShouldNotTakeMoreThan self should: [(Delay forMilliseconds: 100) wait] notTakeMoreThan: 200 milliSeconds.! ----- Method: SUnitExtensionsTest>>validShouldNotTakeMoreThanMilliseconds (in category 'real tests') ----- validShouldNotTakeMoreThanMilliseconds self should: [(Delay forMilliseconds: 100) wait] notTakeMoreThanMilliseconds: 200! TestCase subclass: #SUnitTest instanceVariableNames: 'hasRun hasSetup hasRanOnce' classVariableNames: '' poolDictionaries: '' category: 'SUnit-Tests'! !SUnitTest commentStamp: '<historical>' prior: 0! This is both an example of writing tests and a self test for the SUnit. The tests here are pretty strange, since you want to make sure things blow up. You should not generally have to write tests this complicated in structure, although they will be far more complicated in terms of your own objects- more assertions, more complicated setup. Kent says: "Never forget, however, that if the tests are hard to write, something is probably wrong with the design".! ----- Method: SUnitTest class>>lastStoredRun (in category 'history') ----- lastStoredRun ^ ((Dictionary new) add: (#passed->((Set new) add: #testWithExceptionDo; add: #testRan; add: #testAssert; add: #testRanOnlyOnce; add: #testDialectLocalizedException; add: #testFail; add: #testDefects; add: #testIsNotRerunOnDebug; add: #testResult; add: #testRunning; add: #testError; add: #testException; add: #testShould; add: #testSuite; yourself)); add: (#timeStamp->'22 November 2008 10:11:35 pm'); add: (#failures->((Set new))); add: (#errors->((Set new))); yourself)! ----- Method: SUnitTest>>assertForTestResult:runCount:passed:failed:errors: (in category 'private') ----- assertForTestResult: aResult runCount: aRunCount passed: aPassedCount failed: aFailureCount errors: anErrorCount self assert: aResult runCount = aRunCount; assert: aResult passedCount = aPassedCount; assert: aResult failureCount = aFailureCount; assert: aResult errorCount = anErrorCount ! ----- Method: SUnitTest>>error (in category 'private') ----- error 3 zork ! ----- Method: SUnitTest>>errorShouldntRaise (in category 'testing') ----- errorShouldntRaise self shouldnt: [self someMessageThatIsntUnderstood] raise: Notification new ! ----- Method: SUnitTest>>fail (in category 'private') ----- fail self assert: false ! ----- Method: SUnitTest>>hasRun (in category 'accessing') ----- hasRun ^hasRun ! ----- Method: SUnitTest>>hasSetup (in category 'accessing') ----- hasSetup ^hasSetup ! ----- Method: SUnitTest>>noop (in category 'private') ----- noop ! ----- Method: SUnitTest>>setRun (in category 'private') ----- setRun hasRun := true ! ----- Method: SUnitTest>>setUp (in category 'running') ----- setUp hasSetup := true ! ----- Method: SUnitTest>>testAssert (in category 'testing') ----- testAssert self assert: true. self deny: false ! ----- Method: SUnitTest>>testAssertIdentical (in category 'testing') ----- testAssertIdentical | a b | a := 'foo'. b := 'bar'. self should: [self assert: a identical: b] raise: TestFailure. [self assert: a identical: b] on: TestFailure do: [:e | |error| error := e messageText. self assert: (error includesSubString: a) description: 'Error message doesn''t include the expected value'. self assert: (error includesSubString: b) description: 'Error message doesn''t include the expected value'].! ----- Method: SUnitTest>>testAssertIdenticalDescription (in category 'testing') ----- testAssertIdenticalDescription | a b | a := 'foo'. b := a copy. self should: [self assert: a identical: b description: 'A desciption'] raise: TestFailure. [self assert: a identical: b description: 'A desciption'] on: TestFailure do: [:e | |error| error := e messageText. self assert: (error includesSubString: 'A desciption') description: 'Error message doesn''t give you the description'].! ----- Method: SUnitTest>>testAssertIdenticalWithEqualObjects (in category 'testing') ----- testAssertIdenticalWithEqualObjects | a b | a := 'foo'. b := a copy. self should: [self assert: a identical: b] raise: TestFailure. [self assert: a identical: b] on: TestFailure do: [:e | |error| error := e messageText. self assert: (error includesSubString: 'not identical') description: 'Error message doesn''t say the two things aren''t identical'].! ----- Method: SUnitTest>>testDefects (in category 'testing') ----- testDefects | result suite error failure | suite := TestSuite new. suite addTest: (error := self class selector: #error). suite addTest: (failure := self class selector: #fail). result := suite run. self assert: result defects asArray = (Array with: error with: failure). self assertForTestResult: result runCount: 2 passed: 0 failed: 1 errors: 1 ! ----- Method: SUnitTest>>testDialectLocalizedException (in category 'testing') ----- testDialectLocalizedException self should: [TestResult signalFailureWith: 'Foo'] raise: TestResult failure. self should: [TestResult signalErrorWith: 'Foo'] raise: TestResult error. ! ----- Method: SUnitTest>>testError (in category 'testing') ----- testError | case result | case := self class selector: #error. result := case run. self assertForTestResult: result runCount: 1 passed: 0 failed: 0 errors: 1. case := self class selector: #errorShouldntRaise. result := case run. self assertForTestResult: result runCount: 1 passed: 0 failed: 0 errors: 1 ! ----- Method: SUnitTest>>testException (in category 'testing') ----- testException self should: [self error: 'foo'] raise: TestResult error ! ----- Method: SUnitTest>>testFail (in category 'testing') ----- testFail | case result | case := self class selector: #fail. result := case run. self assertForTestResult: result runCount: 1 passed: 0 failed: 1 errors: 0 ! ----- Method: SUnitTest>>testRan (in category 'testing') ----- testRan | case | case := self class selector: #setRun. case run. self assert: case hasSetup. self assert: case hasRun ! ----- Method: SUnitTest>>testRanOnlyOnce (in category 'testing') ----- testRanOnlyOnce self assert: hasRanOnce ~= true. hasRanOnce := true ! ----- Method: SUnitTest>>testResult (in category 'testing') ----- testResult | case result | case := self class selector: #noop. result := case run. self assertForTestResult: result runCount: 1 passed: 1 failed: 0 errors: 0 ! ----- Method: SUnitTest>>testRunning (in category 'testing') ----- testRunning (Delay forSeconds: 2) wait ! ----- Method: SUnitTest>>testSelectorWithArg: (in category 'testing') ----- testSelectorWithArg: anObject "should not result in error"! ----- Method: SUnitTest>>testShould (in category 'testing') ----- testShould self should: [true]; shouldnt: [false] ! ----- Method: SUnitTest>>testSuite (in category 'testing') ----- testSuite | suite result | suite := TestSuite new. suite addTest: (self class selector: #noop); addTest: (self class selector: #fail); addTest: (self class selector: #error). result := suite run. self assertForTestResult: result runCount: 3 passed: 1 failed: 1 errors: 1 ! ----- Method: SUnitTest>>testTestTimeout (in category 'testing') ----- testTestTimeout self should:[(Delay forSeconds: 6) wait] raise: TestFailure. ! ----- Method: SUnitTest>>testTestTimeoutLoop (in category 'testing') ----- testTestTimeoutLoop <timeout: 1> self should:[[] repeat] raise: TestFailure. ! ----- Method: SUnitTest>>testTestTimeoutTag (in category 'testing') ----- testTestTimeoutTag <timeout: 1> self should:[(Delay forSeconds: 3) wait] raise: TestFailure. ! ----- Method: SUnitTest>>testWithExceptionDo (in category 'testing') ----- testWithExceptionDo self should: [self error: 'foo'] raise: TestResult error withExceptionDo: [:exception | self assert: (exception description includesSubString: 'foo') ] ! TestCase subclass: #SimpleTestResourceTestCase instanceVariableNames: 'resource' classVariableNames: '' poolDictionaries: '' category: 'SUnit-Tests'! ----- Method: SimpleTestResourceTestCase class>>lastStoredRun (in category 'history') ----- lastStoredRun ^ ((Dictionary new) add: (#passed->((Set new) add: #testResourceInitRelease; add: #testResourcesCollection; add: #testRan; yourself)); add: (#timeStamp->'22 November 2008 10:11:35 pm'); add: (#failures->((Set new))); add: (#errors->((Set new))); yourself)! ----- Method: SimpleTestResourceTestCase class>>resources (in category 'not categorized') ----- resources ^Set new add: SimpleTestResource; yourself ! ----- Method: SimpleTestResourceTestCase>>dummy (in category 'not categorized') ----- dummy self assert: true ! ----- Method: SimpleTestResourceTestCase>>error (in category 'not categorized') ----- error 'foo' odd ! ----- Method: SimpleTestResourceTestCase>>fail (in category 'not categorized') ----- fail self assert: false ! ----- Method: SimpleTestResourceTestCase>>setRun (in category 'not categorized') ----- setRun resource setRun ! ----- Method: SimpleTestResourceTestCase>>setUp (in category 'not categorized') ----- setUp resource := SimpleTestResource current ! ----- Method: SimpleTestResourceTestCase>>testRan (in category 'not categorized') ----- testRan | case | case := self class selector: #setRun. case run. self assert: resource hasSetup. self assert: resource hasRun ! ----- Method: SimpleTestResourceTestCase>>testResourceInitRelease (in category 'not categorized') ----- testResourceInitRelease | result suite error failure | suite := TestSuite new. suite addTest: (error := self class selector: #error). suite addTest: (failure := self class selector: #fail). suite addTest: (self class selector: #dummy). result := suite run. self assert: resource hasSetup ! ----- Method: SimpleTestResourceTestCase>>testResourcesCollection (in category 'not categorized') ----- testResourcesCollection | collection | collection := self resources. self assert: collection size = 1 ! ----- Method: TestCase class>>addTestsFor:toSuite: (in category 'building suites') ----- addTestsFor: classNameString toSuite: suite | cls | cls := Smalltalk at: classNameString ifAbsent: [ ^suite ]. ^cls isAbstract ifTrue: [ cls allSubclasses do: [ :each | each isAbstract ifFalse: [ each addToSuiteFromSelectors: suite ] ]. suite] ifFalse: [ cls addToSuiteFromSelectors: suite ] ! ----- Method: TestCase class>>addToSuite:fromMethods: (in category 'building suites') ----- addToSuite: suite fromMethods: testMethods testMethods do: [ :selector | suite addTest: (self selector: selector) ]. ^suite! ----- Method: TestCase class>>addToSuiteFromSelectors: (in category 'building suites') ----- addToSuiteFromSelectors: suite ^self addToSuite: suite fromMethods: (self shouldInheritSelectors ifTrue: [ self allTestSelectors ] ifFalse: [self testSelectors ])! ----- Method: TestCase class>>allTestSelectors (in category 'accessing') ----- allTestSelectors ^(self allSelectors asArray select: [ :each | each isTestSelector and: [ each numArgs isZero ] ]) sort ! ----- Method: TestCase class>>buildSuite (in category 'building suites') ----- buildSuite | suite | suite := self suiteClass new. ^ self isAbstract ifTrue: [ suite name: self name asString. self allSubclasses do: [:each | each isAbstract ifFalse: [each addToSuiteFromSelectors: suite]]. suite] ifFalse: [self addToSuiteFromSelectors: suite]! ----- Method: TestCase class>>buildSuiteFromAllSelectors (in category 'building suites') ----- buildSuiteFromAllSelectors ^self buildSuiteFromMethods: self allTestSelectors ! ----- Method: TestCase class>>buildSuiteFromLocalSelectors (in category 'building suites') ----- buildSuiteFromLocalSelectors ^self buildSuiteFromMethods: self testSelectors ! ----- Method: TestCase class>>buildSuiteFromMethods: (in category 'building suites') ----- buildSuiteFromMethods: testMethods | suite | suite := (self suiteClass new) name: self name asString; yourself. ^self addToSuite: suite fromMethods: testMethods! ----- Method: TestCase class>>buildSuiteFromSelectors (in category 'building suites') ----- buildSuiteFromSelectors ^self shouldInheritSelectors ifTrue: [self buildSuiteFromAllSelectors] ifFalse: [self buildSuiteFromLocalSelectors] ! ----- Method: TestCase class>>coverage (in category 'coverage') ----- coverage "returns the coverage determined by a simple static analysis of test coverage made by the receiver on a class that is identified by the name of the receiver. We assume that SetTest test Set." | cls className | (self name endsWith: 'Test') ifFalse: [self error: 'Please, use #coverageForClass: instead']. className := self name copyFrom: 1 to: (self name size - 'Test' size). cls := Smalltalk at: className asSymbol ifAbsent: [self error: 'Please, use #coverageForClass: instead']. "May happen with Transcript" cls isBehavior ifFalse: [cls := cls class]. ^ self coverageForClass: cls! ----- Method: TestCase class>>coverageAsString (in category 'coverage') ----- coverageAsString | cov className | cov := self coverage first asInteger. "coverage already checks that the name is ends with 'Test' and if the class tested exists" className := self name copyFrom: 1 to: (self name size - 'Test' size). ^ self name asString, ' covers ', cov asString, '% of ', className.! ----- Method: TestCase class>>coverageForClass: (in category 'coverage') ----- coverageForClass: cls "returns the test coverage of all the methods included inherited ones" ^ self coverageForClass: cls until: ProtoObject! ----- Method: TestCase class>>coverageForClass:until: (in category 'coverage') ----- coverageForClass: cls until: aRootClass "returns the test coverage of all the methods included inherited ones but stopping at aRootClass included" | definedMethods testedMethods untestedMethods | definedMethods := cls allSelectorsAboveUntil: aRootClass. definedMethods size = 0 ifTrue: [^ {0. Set new}]. testedMethods := self methodDictionary inject: Set new into: [:sums :cm | sums union: cm messages]. testedMethods := testedMethods reject: [:sel | (definedMethods includes: sel) not]. untestedMethods := definedMethods select: [:selector | (testedMethods includes: selector) not]. ^ { (testedMethods size * 100 / definedMethods size) asFloat . untestedMethods} ! ----- Method: TestCase class>>coveragePercentage (in category 'coverage') ----- coveragePercentage ^ self coverage first! ----- Method: TestCase class>>debug: (in category 'instance creation') ----- debug: aSymbol ^(self selector: aSymbol) debug ! ----- Method: TestCase class>>generateLastStoredRunMethod (in category 'history') ----- generateLastStoredRunMethod self shouldGenerateLastStoredRunMethod ifTrue: [ self class compile: (self lastRunMethodNamed: #lastStoredRun) classified: 'history' ]! ----- Method: TestCase class>>hasMethodBeenRun: (in category 'testing') ----- hasMethodBeenRun: aSelector ^ ((self lastRun at: #errors), (self lastRun at: #failures), (self lastRun at: #passed)) includes: aSelector! ----- Method: TestCase class>>history (in category 'history') ----- history ^ history ifNil: [ history := self newTestDictionary ]! ----- Method: TestCase class>>history: (in category 'history') ----- history: aDictionary history := aDictionary! ----- Method: TestCase class>>initialize (in category 'initialize - event') ----- initialize super initialize. SystemChangeNotifier uniqueInstance notify: self ofSystemChangesOfItem: #method using: #methodChanged:.! ----- Method: TestCase class>>isAbstract (in category 'testing') ----- isAbstract "Override to true if a TestCase subclass is Abstract and should not have TestCase instances built from it" ^self name = #TestCase ! ----- Method: TestCase class>>isTestClass (in category 'testing') ----- isTestClass ^ true! ----- Method: TestCase class>>lastRun (in category 'history') ----- lastRun ^ TestResult historyFor: self! ----- Method: TestCase class>>lastRunMethodNamed: (in category 'history') ----- lastRunMethodNamed: aSelector ^ String streamContents: [:str | str nextPutAll: aSelector asString ;cr. str tab; nextPutAll: '^ ', (self lastRun) storeString] ! ----- Method: TestCase class>>lastStoredRun (in category 'history') ----- lastStoredRun ^ ((Dictionary new) add: (#failures->#()); add: (#passed->#()); add: (#errors->#()); yourself)! ----- Method: TestCase class>>localCoverage (in category 'coverage') ----- localCoverage "returns the coverage determined by a simple static analysis of test coverage made by the receiver on a class that is identified by the name of the receiver. We assume that SetTest test Set. The computation of the coverage takes only into account the methods defined locally in the tested class. See coverage for a more global coverage" | cls className | (self name endsWith: 'Test') ifFalse: [self error: 'Please, use #localCoverageForClass: instead']. className := self name copyFrom: 1 to: (self name size - 'Test' size). cls := Smalltalk at: className asSymbol ifAbsent: [self error: 'Please, use #localCoverageForClass: instead']. cls isBehavior ifFalse: [cls := cls class]. ^ self localCoverageForClass: cls! ----- Method: TestCase class>>localCoverageAsString (in category 'coverage') ----- localCoverageAsString | cov className | cov := self localCoverage first asInteger. "coverage already checks that the name is ends with 'Test' and if the class tested exists" className := self name copyFrom: 1 to: (self name size - 'Test' size). ^ self name asString, ' covers ', cov asString, '% of ', className.! ----- Method: TestCase class>>localCoverageForClass: (in category 'coverage') ----- localCoverageForClass: cls | definedMethods testedMethods untestedMethods | definedMethods := cls selectors asSet. "It happens for IdentityBag / IdentityBagTest" definedMethods size = 0 ifTrue: [^ {0. Set new}]. testedMethods := self methodDictionary inject: Set new into: [:sums :cm | sums union: cm messages]. "testedMethods contains all the methods send in test methods, which probably contains methods that have nothign to do with collection" testedMethods := testedMethods reject: [:sel | (definedMethods includes: sel) not]. untestedMethods := definedMethods select: [:selector | (testedMethods includes: selector) not]. ^ { (testedMethods size * 100 / definedMethods size) asFloat . untestedMethods} ! ----- Method: TestCase class>>localCoveragePercentage (in category 'coverage') ----- localCoveragePercentage ^ self localCoverage first! ----- Method: TestCase class>>methodChanged: (in category 'initialize - event') ----- methodChanged: anEvent "Remove the changed method from the known test results." | cls sel | anEvent item isCompiledMethod ifFalse: [ ^ self ]. cls := anEvent item methodClass. (cls inheritsFrom: TestCase) ifFalse: [^ self]. sel := anEvent item selector. (sel beginsWith: 'test') ifFalse: [^ self]. TestResult removeFromTestHistory: sel in: cls. ! ----- Method: TestCase class>>methodFailed: (in category 'testing') ----- methodFailed: aSelector ^ (self lastRun at: #failures) includes: aSelector! ----- Method: TestCase class>>methodPassed: (in category 'testing') ----- methodPassed: aSelector ^ (self lastRun at: #passed) includes: aSelector! ----- Method: TestCase class>>methodProgressed: (in category 'testing') ----- methodProgressed: aSelector ^ ((self storedMethodRaisedError: aSelector) or: [self storedMethodFailed: aSelector]) and: [self methodPassed: aSelector] ! ----- Method: TestCase class>>methodRaisedError: (in category 'testing') ----- methodRaisedError: aSelector ^ (self lastRun at: #errors) includes: aSelector! ----- Method: TestCase class>>methodRegressed: (in category 'testing') ----- methodRegressed: aSelector ^ (self storedMethodPassed: aSelector) and: [(self methodFailed: aSelector) or: [self methodRaisedError: aSelector]]! ----- Method: TestCase class>>newTestDictionary (in category 'history') ----- newTestDictionary ^ Dictionary new at: #timeStamp put: TimeStamp now; at: #passed put: Set new; at: #failures put: Set new; at: #errors put: Set new; yourself ! ----- Method: TestCase class>>resetHistory (in category 'history') ----- resetHistory history := nil! ----- Method: TestCase class>>resources (in category 'accessing') ----- resources ^#() ! ----- Method: TestCase class>>run: (in category 'instance creation') ----- run: aSymbol ^(self selector: aSymbol) run ! ----- Method: TestCase class>>selector: (in category 'instance creation') ----- selector: aSymbol ^self new setTestSelector: aSymbol ! ----- Method: TestCase class>>shouldGenerateLastStoredRunMethod (in category 'history') ----- shouldGenerateLastStoredRunMethod | sameRun | (self class methodDictionary includesKey: #lastStoredRun) ifFalse: [^ true]. sameRun := #(#passed #failures #errors) inject: true into: [ :ok :set | ok and: [(self lastRun at: set) = (self lastStoredRun at: set) ]]. ^ sameRun not ! ----- Method: TestCase class>>shouldInheritSelectors (in category 'testing') ----- shouldInheritSelectors "I should inherit from an Abstract superclass but not from a concrete one by default, unless I have no testSelectors in which case I must be expecting to inherit them from my superclass. If a test case with selectors wants to inherit selectors from a concrete superclass, override this to true in that subclass." ^self superclass isAbstract or: [self testSelectors isEmpty] "$QA Ignore:Sends system method(superclass)$" ! ----- Method: TestCase class>>storedMethodFailed: (in category 'testing') ----- storedMethodFailed: aSelector ^ (self lastStoredRun at: #failures) includes: aSelector! ----- Method: TestCase class>>storedMethodPassed: (in category 'testing') ----- storedMethodPassed: aSelector ^ (self lastStoredRun at: #passed) includes: aSelector! ----- Method: TestCase class>>storedMethodRaisedError: (in category 'testing') ----- storedMethodRaisedError: aSelector ^ (self lastStoredRun at: #errors) includes: aSelector! ----- Method: TestCase class>>suite (in category 'instance creation') ----- suite ^self buildSuite ! ----- Method: TestCase class>>suiteClass (in category 'building suites') ----- suiteClass ^TestSuite ! ----- Method: TestCase class>>sunitVersion (in category 'accessing') ----- sunitVersion ^'3.1' ! ----- Method: TestCase class>>testSelectors (in category 'Accessing') ----- testSelectors ^(self selectors asArray select: [ :each | (each beginsWith: 'test') and: [ each numArgs isZero ] ]) sort! ----- Method: TestCase>>addDependentToHierachy: (in category 'dependencies') ----- addDependentToHierachy: anObject "an empty method. for Composite compability with TestSuite" ! ----- Method: TestCase>>assert: (in category 'accessing') ----- assert: aBooleanOrBlock aBooleanOrBlock value ifFalse: [self signalFailure: 'Assertion failed'] ! ----- Method: TestCase>>assert:description: (in category 'accessing') ----- assert: aBooleanOrBlock description: aStringOrBlock aBooleanOrBlock value ifFalse: [ | description | description := aStringOrBlock value. self logFailure: description. TestResult failure signal: description ] ! ----- Method: TestCase>>assert:description:resumable: (in category 'accessing') ----- assert: aBooleanOrBlock description: aString resumable: resumableBoolean | exception | aBooleanOrBlock value ifFalse: [self logFailure: aString. exception := resumableBoolean ifTrue: [TestResult resumableFailure] ifFalse: [TestResult failure]. exception signal: aString] ! ----- Method: TestCase>>assert:equals: (in category 'accessing') ----- assert: expected equals: actual ^self assert: expected = actual description: [ self comparingStringBetween: expected and: actual ] ! ----- Method: TestCase>>assert:equals:description: (in category 'accessing') ----- assert: expected equals: actual description: aString ^self assert: expected = actual description: [ aString , ': ', (self comparingStringBetween: expected and: actual) ]! ----- Method: TestCase>>assert:identical: (in category 'accessing') ----- assert: expected identical: actual ^self assert: expected == actual description: [ self comparingStringBetweenIdentical: expected and: actual ] ! ----- Method: TestCase>>assert:identical:description: (in category 'accessing') ----- assert: expected identical: actual description: aString ^self assert: expected == actual description: [ aString , ': ', (self comparingStringBetweenIdentical: expected and: actual) ]! ----- Method: TestCase>>comparingStringBetween:and: (in category 'private') ----- comparingStringBetween: expected and: actual ^ String streamContents: [:stream | stream nextPutAll: 'Expected '; nextPutAll: (expected printStringLimitedTo: 10); nextPutAll: ' but was '; nextPutAll: (actual printStringLimitedTo: 10); nextPutAll: '.' ]! ----- Method: TestCase>>comparingStringBetweenIdentical:and: (in category 'private') ----- comparingStringBetweenIdentical: expected and: actual ^ 'Expected {1} and actual {2} are not identical.' format: { expected printStringLimitedTo: 10. actual printStringLimitedTo: 10. }! ----- Method: TestCase>>debug (in category 'running') ----- debug self resources do: [ : res | res isAvailable ifFalse: [ ^ res signalInitializationError ] ]. [ self runCase ] ensure: [ self resources do: [ : each | each reset ] ]! ----- Method: TestCase>>debugAsFailure (in category 'running') ----- debugAsFailure | semaphore | semaphore := Semaphore new. self resources do: [:res | res isAvailable ifFalse: [^res signalInitializationError]]. [semaphore wait. self resources do: [:each | each reset]] fork. (self class selector: testSelector) runCaseAsFailure: semaphore.! ----- Method: TestCase>>defaultTimeout (in category 'accessing') ----- defaultTimeout "Answer the default timeout to use for tests in this test case. The timeout is a value in seconds." ^5 "seconds"! ----- Method: TestCase>>deny: (in category 'accessing') ----- deny: aBooleanOrBlock self assert: aBooleanOrBlock value not ! ----- Method: TestCase>>deny:description: (in category 'accessing') ----- deny: aBooleanOrBlock description: aString self assert: aBooleanOrBlock value not description: aString ! ----- Method: TestCase>>deny:description:resumable: (in category 'accessing') ----- deny: aBooleanOrBlock description: aString resumable: resumableBoolean self assert: aBooleanOrBlock value not description: aString resumable: resumableBoolean ! ----- Method: TestCase>>executeShould:inScopeOf: (in category 'private') ----- executeShould: aBlock inScopeOf: anExceptionalEvent ^[aBlock value. false] on: anExceptionalEvent do: [:ex | ex return: true] ! ----- Method: TestCase>>executeShould:inScopeOf:withDescriptionContaining: (in category 'private') ----- executeShould: aBlock inScopeOf: anExceptionalEvent withDescriptionContaining: aString ^[aBlock value. false] on: anExceptionalEvent do: [:ex | ex return: (ex description includesSubString: aString) ] ! ----- Method: TestCase>>executeShould:inScopeOf:withDescriptionNotContaining: (in category 'private') ----- executeShould: aBlock inScopeOf: anExceptionalEvent withDescriptionNotContaining: aString ^[aBlock value. false] on: anExceptionalEvent do: [:ex | ex return: (ex description includesSubString: aString) not ] ! ----- Method: TestCase>>executeShould:inScopeOf:withExceptionDo: (in category 'extensions') ----- executeShould: aBlock inScopeOf: anException withExceptionDo: anotherBlock ^[aBlock value. false] on: anException do: [:exception | anotherBlock value: exception. exception return: true]! ----- Method: TestCase>>expectedFailures (in category 'testing') ----- expectedFailures ^ Array new! ----- Method: TestCase>>fail (in category 'extensions') ----- fail ^self assert: false! ----- Method: TestCase>>fail: (in category 'extensions') ----- fail: aString ^self assert: false description: aString.! ----- Method: TestCase>>failureLog (in category 'running') ----- failureLog ^Transcript ! ----- Method: TestCase>>isLogging (in category 'running') ----- isLogging "By default, we're not logging failures. If you override this in a subclass, make sure that you override #failureLog" ^false ! ----- Method: TestCase>>logFailure: (in category 'running') ----- logFailure: aString self isLogging ifTrue: [ self failureLog cr; nextPutAll: aString; flush] ! ----- Method: TestCase>>openDebuggerOnFailingTestMethod (in category 'running') ----- openDebuggerOnFailingTestMethod "SUnit has halted one step in front of the failing test method. Step over the 'self halt' and send into 'self perform: testSelector' to see the failure from the beginning" self halt; performTest! ----- Method: TestCase>>performTest (in category 'private') ----- performTest self perform: testSelector asSymbol ! ----- Method: TestCase>>printOn: (in category 'printing') ----- printOn: aStream testSelector ifNil: [super printOn: aStream] ifNotNil: [aStream nextPutAll: self class printString; nextPutAll: '>>#'; nextPutAll: testSelector] ! ----- Method: TestCase>>removeDependentFromHierachy: (in category 'dependencies') ----- removeDependentFromHierachy: anObject "an empty method. for Composite compability with TestSuite" ! ----- Method: TestCase>>resources (in category 'accessing') ----- resources | allResources resourceQueue | allResources := Set new. resourceQueue := OrderedCollection new. resourceQueue addAll: self class resources. [resourceQueue isEmpty] whileFalse: [ | next | next := resourceQueue removeFirst. allResources add: next. resourceQueue addAll: next resources]. ^allResources ! ----- Method: TestCase>>run (in category 'running') ----- run | result | result := TestResult new. self run: result. ^result ! ----- Method: TestCase>>run: (in category 'running') ----- run: aResult aResult runCase: self. ! ----- Method: TestCase>>runCase (in category 'running') ----- runCase "Run this TestCase. Time out if the test takes too long." [self timeout: [self setUp] after: self timeoutForSetUp. self timeout: [self performTest] after: self timeoutForTest] ensure: [self tearDown]! ----- Method: TestCase>>runCaseAsFailure: (in category 'running') ----- runCaseAsFailure: aSemaphore [self setUp. self openDebuggerOnFailingTestMethod] ensure: [ self tearDown. aSemaphore signal]! ----- Method: TestCase>>selector (in category 'accessing') ----- selector ^testSelector ! ----- Method: TestCase>>setTestSelector: (in category 'private') ----- setTestSelector: aSymbol testSelector := aSymbol ! ----- Method: TestCase>>setUp (in category 'running') ----- setUp! ----- Method: TestCase>>should: (in category 'accessing') ----- should: aBlock self assert: aBlock value ! ----- Method: TestCase>>should:description: (in category 'accessing') ----- should: aBlock description: aString self assert: aBlock value description: aString ! ----- Method: TestCase>>should:notTakeMoreThan: (in category 'extensions') ----- should: aBlock notTakeMoreThan: aDuration "Evaluate aBlock in a forked process and if it takes more than anInteger milliseconds to run we terminate the process and report a test failure. It'' important to use the active process for the test failure so that the failure reporting works correctly in the context of the exception handlers." | evaluated evaluationProcess result delay testProcess | evaluated := false. delay := Delay forDuration: aDuration. testProcess := Processor activeProcess. "Create a new process to evaluate aBlock" evaluationProcess := [ result := aBlock value. evaluated := true. delay unschedule. testProcess resume ] forkNamed: 'Process to evaluate should: notTakeMoreThanMilliseconds:'. "Wait the milliseconds they asked me to" delay wait. "After this point either aBlock was evaluated or not..." evaluated ifFalse: [ evaluationProcess terminate. self assert: false description: ('Block evaluation took more than the expected <1p>' expandMacrosWith: aDuration)]. ^result! ----- Method: TestCase>>should:notTakeMoreThanMilliseconds: (in category 'extensions') ----- should: aBlock notTakeMoreThanMilliseconds: anInteger "For compatibility with other Smalltalks" self should: aBlock notTakeMoreThan: (Duration milliSeconds: anInteger).! ----- Method: TestCase>>should:raise: (in category 'accessing') ----- should: aBlock raise: anExceptionalEvent ^self assert: (self executeShould: aBlock inScopeOf: anExceptionalEvent) ! ----- Method: TestCase>>should:raise:description: (in category 'accessing') ----- should: aBlock raise: anExceptionalEvent description: aString ^self assert: (self executeShould: aBlock inScopeOf: anExceptionalEvent) description: aString ! ----- Method: TestCase>>should:raise:whoseDescriptionDoesNotInclude:description: (in category 'accessing') ----- should: aBlock raise: anExceptionalEvent whoseDescriptionDoesNotInclude: subString description: aString ^self assert: (self executeShould: aBlock inScopeOf: anExceptionalEvent withDescriptionNotContaining: subString) description: aString ! ----- Method: TestCase>>should:raise:whoseDescriptionIncludes:description: (in category 'accessing') ----- should: aBlock raise: anExceptionalEvent whoseDescriptionIncludes: subString description: aString ^self assert: (self executeShould: aBlock inScopeOf: anExceptionalEvent withDescriptionContaining: subString) description: aString ! ----- Method: TestCase>>should:raise:withExceptionDo: (in category 'extensions') ----- should: aBlock raise: anException withExceptionDo: anotherBlock ^self assert: (self executeShould: aBlock inScopeOf: anException withExceptionDo: anotherBlock)! ----- Method: TestCase>>shouldFix: (in category 'extensions') ----- shouldFix: aBlock ^self should: aBlock raise: Exception! ----- Method: TestCase>>shouldPass (in category 'testing') ----- shouldPass "Unless the selector is in the list we get from #expectedFailures, we expect it to pass" ^ (self expectedFailures includes: testSelector) not! ----- Method: TestCase>>shouldnt: (in category 'accessing') ----- shouldnt: aBlock self deny: aBlock value ! ----- Method: TestCase>>shouldnt:description: (in category 'accessing') ----- shouldnt: aBlock description: aString self deny: aBlock value description: aString ! ----- Method: TestCase>>shouldnt:raise: (in category 'accessing') ----- shouldnt: aBlock raise: anExceptionalEvent ^ [ aBlock value ] on: anExceptionalEvent do: [:e | self fail: 'Block raised ', e className, ': ', e messageText].! ----- Method: TestCase>>shouldnt:raise:description: (in category 'accessing') ----- shouldnt: aBlock raise: anExceptionalEvent description: aString ^self assert: (self executeShould: aBlock inScopeOf: anExceptionalEvent) not description: aString ! ----- Method: TestCase>>shouldnt:raise:whoseDescriptionDoesNotInclude:description: (in category 'accessing') ----- shouldnt: aBlock raise: anExceptionalEvent whoseDescriptionDoesNotInclude: subString description: aString ^self assert: (self executeShould: aBlock inScopeOf: anExceptionalEvent withDescriptionNotContaining: subString) not description: aString ! ----- Method: TestCase>>shouldnt:raise:whoseDescriptionIncludes:description: (in category 'accessing') ----- shouldnt: aBlock raise: anExceptionalEvent whoseDescriptionIncludes: subString description: aString ^self assert: (self executeShould: aBlock inScopeOf: anExceptionalEvent withDescriptionContaining: subString) not description: aString ! ----- Method: TestCase>>signalFailure: (in category 'accessing') ----- signalFailure: aString TestResult failure signal: aString! ----- Method: TestCase>>tearDown (in category 'running') ----- tearDown! ----- Method: TestCase>>timeout: (in category 'accessing') ----- timeout: seconds "The timeout for a test should normally be set with a method annotation. However, for tests that are expected to run in images that do not support method annotations, the value may be set by setting the value from the #setUp method (i.e. prior to running the test method)." timeout := seconds! ----- Method: TestCase>>timeout:after: (in category 'running') ----- timeout: aBlock after: seconds "Evaluate the argument block. Time out if the evaluation is not complete after the given number of seconds. Handle the situation that a timeout may occur after a failure (during debug)" | theProcess delay watchdog | "the block will be executed in the current process" theProcess := Processor activeProcess. delay := Delay forSeconds: seconds. "make a watchdog process" watchdog := [ delay wait. "wait for timeout or completion" theProcess ifNotNil:[ theProcess signalException: (TestFailure new messageText: 'Test timed out') ] ] newProcess. "Watchdog needs to run at high priority to do its job (but not at timing priority)" watchdog priority: Processor timingPriority-1. "catch the timeout signal" watchdog resume. "start up the watchdog" ^[aBlock on: TestFailure, Error, Halt do:[:ex| theProcess := nil. ex pass. ]] ensure:[ "evaluate the receiver" theProcess := nil. "it has completed, so ..." delay delaySemaphore signal. "arrange for the watchdog to exit" ]! ----- Method: TestCase>>timeoutForSetUp (in category 'accessing') ----- timeoutForSetUp "Answer the timeout to use for setUp" | method | method := self class lookupSelector: testSelector asSymbol. (method pragmaAt: #timeout:) ifNotNil:[:tag| ^tag arguments first]. ^self defaultTimeout! ----- Method: TestCase>>timeoutForTest (in category 'accessing') ----- timeoutForTest "Answer the timeout to use for this test" | method | method := self class lookupSelector: testSelector asSymbol. (method pragmaAt: #timeout:) ifNotNil:[:tag| ^tag arguments first]. ^timeout ifNil: [self defaultTimeout]! Object subclass: #TestResource instanceVariableNames: 'name description' classVariableNames: '' poolDictionaries: '' category: 'SUnit-Kernel'! TestResource class instanceVariableNames: 'current'! TestResource class instanceVariableNames: 'current'! TestResource subclass: #SimpleTestResource instanceVariableNames: 'runningState hasRun hasSetup hasRanOnce' classVariableNames: '' poolDictionaries: '' category: 'SUnit-Tests'! ----- Method: SimpleTestResource>>hasRun (in category 'testing') ----- hasRun ^hasRun ! ----- Method: SimpleTestResource>>hasSetup (in category 'testing') ----- hasSetup ^hasSetup ! ----- Method: SimpleTestResource>>isAvailable (in category 'testing') ----- isAvailable ^self runningState == self startedStateSymbol ! ----- Method: SimpleTestResource>>runningState (in category 'accessing') ----- runningState ^runningState ! ----- Method: SimpleTestResource>>runningState: (in category 'accessing') ----- runningState: aSymbol runningState := aSymbol ! ----- Method: SimpleTestResource>>setRun (in category 'running') ----- setRun hasRun := true ! ----- Method: SimpleTestResource>>setUp (in category 'running') ----- setUp self runningState: self startedStateSymbol. hasSetup := true ! ----- Method: SimpleTestResource>>startedStateSymbol (in category 'running') ----- startedStateSymbol ^#started ! ----- Method: SimpleTestResource>>stoppedStateSymbol (in category 'running') ----- stoppedStateSymbol ^#stopped ! ----- Method: SimpleTestResource>>tearDown (in category 'running') ----- tearDown self runningState: self stoppedStateSymbol ! ----- Method: TestResource class>>current (in category 'accessing') ----- current ^ current ifNil: [ current := self new] ! ----- Method: TestResource class>>current: (in category 'accessing') ----- current: aTestResource current := aTestResource ! ----- Method: TestResource class>>isAbstract (in category 'testing') ----- isAbstract "Override to true if a TestResource subclass is Abstract and should not have TestCase instances built from it" ^self name = #TestResource ! ----- Method: TestResource class>>isAvailable (in category 'testing') ----- isAvailable ^self current notNil and: [self current isAvailable] ! ----- Method: TestResource class>>isUnavailable (in category 'testing') ----- isUnavailable ^self isAvailable not ! ----- Method: TestResource class>>reset (in category 'Creation') ----- reset current ifNotNil: [:oldCurrent | current := nil. oldCurrent tearDown]! ----- Method: TestResource class>>resources (in category 'accessing') ----- resources ^#() ! ----- Method: TestResource class>>signalInitializationError (in category 'creation') ----- signalInitializationError ^TestResult signalErrorWith: 'Resource ' , self name , ' could not be initialized' ! ----- Method: TestResource>>description (in category 'accessing') ----- description ^description ifNil: [ '' ]! ----- Method: TestResource>>description: (in category 'accessing') ----- description: aString description := aString ! ----- Method: TestResource>>initialize (in category 'initializing') ----- initialize super initialize. self setUp ! ----- Method: TestResource>>isAvailable (in category 'testing') ----- isAvailable "override to provide information on the readiness of the resource" ^true ! ----- Method: TestResource>>isUnavailable (in category 'testing') ----- isUnavailable "override to provide information on the readiness of the resource" ^self isAvailable not ! ----- Method: TestResource>>name (in category 'accessing') ----- name ^name ifNil: [ self printString]! ----- Method: TestResource>>name: (in category 'accessing') ----- name: aString name := aString ! ----- Method: TestResource>>printOn: (in category 'printing') ----- printOn: aStream aStream nextPutAll: self class printString ! ----- Method: TestResource>>resources (in category 'accessing') ----- resources ^self class resources ! ----- Method: TestResource>>setUp (in category 'running') ----- setUp "Does nothing. Subclasses should override this to initialize their resource" ! ----- Method: TestResource>>signalInitializationError (in category 'running') ----- signalInitializationError ^self class signalInitializationError ! ----- Method: TestResource>>tearDown (in category 'running') ----- tearDown "Does nothing. Subclasses should override this to tear down their resource" ! Object subclass: #TestResult instanceVariableNames: 'timeStamp failures errors passed' classVariableNames: '' poolDictionaries: '' category: 'SUnit-Kernel'! !TestResult commentStamp: '<historical>' prior: 0! This is a Collecting Parameter for the running of a bunch of tests. TestResult is an interesting object to subclass or substitute. #runCase: is the external protocol you need to reproduce. Kent has seen TestResults that recorded coverage information and that sent email when they were done.! ----- Method: TestResult class>>error (in category 'exceptions') ----- error ^self exError ! ----- Method: TestResult class>>exError (in category 'exceptions') ----- exError ^Error ! ----- Method: TestResult class>>failure (in category 'exceptions') ----- failure ^TestFailure ! ----- Method: TestResult class>>historyAt: (in category 'history') ----- historyAt: aTestCaseClass "I will return the last test dictionary for aTestCaseClass. If none found, I will create a new empty one and link it in the history." ^ aTestCaseClass history ! ----- Method: TestResult class>>historyAt:put: (in category 'history') ----- historyAt: aTestCaseClass put: aDictionary aTestCaseClass history: aDictionary "^ self history at: aTestCaseClass put: aDictionary "! ----- Method: TestResult class>>historyFor: (in category 'history') ----- historyFor: aTestCaseClass "I return the last test dictionary for aTestCaseClass. If none found, I return an empty dictionary but will not link it to the class in the history." | history | history := aTestCaseClass history. history ifNil: [ ^ self newTestDictionary ]. ^ history " ^ self history at: aTestCaseClass ifAbsent: [ self newTestDictionary ]"! ----- Method: TestResult class>>newTestDictionary (in category 'history') ----- newTestDictionary ^ Dictionary new at: #timeStamp put: TimeStamp now; at: #passed put: Set new; at: #failures put: Set new; at: #errors put: Set new; yourself ! ----- Method: TestResult class>>removeFromTestHistory:in: (in category 'history') ----- removeFromTestHistory: aSelector in: aTestCaseClass | lastRun | lastRun := self historyFor: aTestCaseClass. #(#passed #failures #errors) do: [ :set | (lastRun at: set) remove: aSelector ifAbsent: []]. ! ----- Method: TestResult class>>resumableFailure (in category 'exceptions') ----- resumableFailure ^ResumableTestFailure ! ----- Method: TestResult class>>signalErrorWith: (in category 'exceptions') ----- signalErrorWith: aString self error signal: aString ! ----- Method: TestResult class>>signalFailureWith: (in category 'exceptions') ----- signalFailureWith: aString self failure signal: aString ! ----- Method: TestResult class>>updateTestHistoryFor:status: (in category 'history') ----- updateTestHistoryFor: aTestCase status: aSymbol | cls sel | cls := aTestCase class. sel := aTestCase selector. self removeFromTestHistory: sel in: cls. ((self historyAt: cls) at: aSymbol ) add: sel! ----- Method: TestResult>>classesTested (in category 'accessing') ----- classesTested ^ (self tests collect: [ :testCase | testCase class ]) asSet! ----- Method: TestResult>>correctCount (in category 'accessing') ----- correctCount "depreciated - use #passedCount" ^self passedCount ! ----- Method: TestResult>>defects (in category 'accessing') ----- defects ^OrderedCollection new addAll: self errors; addAll: self failures; yourself ! ----- Method: TestResult>>diff: (in category 'diff') ----- diff: aTestResult "Return a collection that contains differences" | passed1Selectors failed1Selectors errors1Selectors passed2Selectors failed2Selectors errors2Selectors | passed1Selectors := self passed collect: [:testCase | testCase selector]. failed1Selectors := self failures collect: [:testCase | testCase selector]. errors1Selectors := self errors collect: [:testCase | testCase selector]. passed2Selectors := aTestResult passed collect: [:testCase | testCase selector]. failed2Selectors := aTestResult failures collect: [:testCase | testCase selector]. errors2Selectors := aTestResult errors collect: [:testCase | testCase selector]. ^ {passed1Selectors copyWithoutAll: passed2Selectors . failed1Selectors copyWithoutAll: failed2Selectors . errors1Selectors copyWithoutAll: errors2Selectors}! ----- Method: TestResult>>dispatchResultsIntoHistory (in category 'history') ----- dispatchResultsIntoHistory self classesTested do: [ :testClass | self class historyAt: testClass put: (self selectResultsForTestCase: testClass) ]. ! ----- Method: TestResult>>errorCount (in category 'accessing') ----- errorCount ^self errors size ! ----- Method: TestResult>>errors (in category 'compatibility') ----- errors ^ self unexpectedErrors! ----- Method: TestResult>>expectedDefectCount (in category 'accessing') ----- expectedDefectCount ^ self expectedDefects size! ----- Method: TestResult>>expectedDefects (in category 'accessing') ----- expectedDefects ^ (errors, failures asOrderedCollection) select: [:each | each shouldPass not] ! ----- Method: TestResult>>expectedPassCount (in category 'accessing') ----- expectedPassCount ^ self expectedPasses size! ----- Method: TestResult>>expectedPasses (in category 'accessing') ----- expectedPasses ^ passed select: [:each | each shouldPass] ! ----- Method: TestResult>>failureCount (in category 'accessing') ----- failureCount ^self failures size ! ----- Method: TestResult>>failures (in category 'compatibility') ----- failures ^ self unexpectedFailures, self unexpectedPasses ! ----- Method: TestResult>>hasErrors (in category 'testing') ----- hasErrors ^self errors size > 0 ! ----- Method: TestResult>>hasFailures (in category 'testing') ----- hasFailures ^self failures size > 0 ! ----- Method: TestResult>>hasPassed (in category 'testing') ----- hasPassed ^ self hasErrors not and: [ self hasFailures not ]! ----- Method: TestResult>>initialize (in category 'initialization') ----- initialize super initialize. passed := OrderedCollection new. failures := Set new. errors := OrderedCollection new. timeStamp := TimeStamp now! ----- Method: TestResult>>isError: (in category 'testing') ----- isError: aTestCase ^self errors includes: aTestCase ! ----- Method: TestResult>>isErrorFor:selector: (in category 'querying') ----- isErrorFor: class selector: selector ^ self errors anySatisfy: [:testCase | testCase class == class and: [testCase selector == selector]]! ----- Method: TestResult>>isFailure: (in category 'testing') ----- isFailure: aTestCase ^self failures includes: aTestCase ! ----- Method: TestResult>>isFailureFor:selector: (in category 'querying') ----- isFailureFor: class selector: selector ^ self failures anySatisfy: [:testCase | testCase class == class and: [testCase selector == selector]]! ----- Method: TestResult>>isPassed: (in category 'testing') ----- isPassed: aTestCase ^self passed includes: aTestCase ! ----- Method: TestResult>>isPassedFor:selector: (in category 'querying') ----- isPassedFor: class selector: selector ^ self passed anySatisfy: [:testCase | testCase class == class and: [testCase selector == selector]]! ----- Method: TestResult>>passed (in category 'compatibility') ----- passed ^ self expectedPasses, self expectedDefects! ----- Method: TestResult>>passedCount (in category 'accessing') ----- passedCount ^self passed size ! ----- Method: TestResult>>printOn: (in category 'printing') ----- printOn: aStream aStream nextPutAll: self runCount printString; nextPutAll: ' run, '; nextPutAll: self expectedPassCount printString; nextPutAll: ' passes, '; nextPutAll: self expectedDefectCount printString; nextPutAll:' expected failures, '; nextPutAll: self unexpectedFailureCount printString; nextPutAll: ' failures, '; nextPutAll: self unexpectedErrorCount printString; nextPutAll:' errors, '; nextPutAll: self unexpectedPassCount printString; nextPutAll:' unexpected passes'.! ----- Method: TestResult>>runCase: (in category 'running') ----- runCase: aTestCase | testCasePassed | testCasePassed := true. [[aTestCase runCase] on: self class failure do: [:signal | failures add: aTestCase. testCasePassed := false. signal return: false]] on: self class error do: [:signal | errors add: aTestCase. testCasePassed := false. signal return: false]. testCasePassed ifTrue: [passed add: aTestCase]! ----- Method: TestResult>>runCount (in category 'accessing') ----- runCount ^ passed size + failures size + errors size! ----- Method: TestResult>>selectResultsForTestCase: (in category 'history') ----- selectResultsForTestCase: aTestCaseClass | passedSelectors errorsSelectors failuresSelectors | passedSelectors := self passed select: [:testCase | testCase class == aTestCaseClass ] thenCollect: [:testCase | testCase selector]. errorsSelectors := self errors select: [:testCase | testCase class == aTestCaseClass ] thenCollect: [:testCase | testCase selector]. failuresSelectors := self failures select: [:testCase | testCase class == aTestCaseClass ] thenCollect: [:testCase | testCase selector]. ^ self class newTestDictionary at: #passed put: passedSelectors asSet; at: #failures put: failuresSelectors asSet; at: #errors put: errorsSelectors asSet; yourself ! ----- Method: TestResult>>tests (in category 'accessing') ----- tests ^(OrderedCollection new: self runCount) addAll: passed; addAll: failures; addAll: errors; yourself! ----- Method: TestResult>>timeStamp (in category 'accessing') ----- timeStamp ^ timeStamp! ----- Method: TestResult>>timeStamp: (in category 'accessing') ----- timeStamp: anObject timeStamp := anObject! ----- Method: TestResult>>unexpectedErrorCount (in category 'accessing') ----- unexpectedErrorCount ^ self unexpectedErrors size! ----- Method: TestResult>>unexpectedErrors (in category 'accessing') ----- unexpectedErrors ^ errors select: [:each | each shouldPass] ! ----- Method: TestResult>>unexpectedFailureCount (in category 'accessing') ----- unexpectedFailureCount ^ self unexpectedFailures size! ----- Method: TestResult>>unexpectedFailures (in category 'accessing') ----- unexpectedFailures ^ failures select: [:each | each shouldPass] ! ----- Method: TestResult>>unexpectedPassCount (in category 'accessing') ----- unexpectedPassCount ^ self unexpectedPasses size! ----- Method: TestResult>>unexpectedPasses (in category 'accessing') ----- unexpectedPasses ^ passed select: [:each | each shouldPass not] ! ----- Method: TestResult>>updateResultsInHistory (in category 'history') ----- updateResultsInHistory #(#passed #failures #errors) do: [ :status | (self perform: status) do: [ :testCase | self class updateTestHistoryFor: testCase status: status ] ]! Object subclass: #TestSuite instanceVariableNames: 'tests resources name' classVariableNames: '' poolDictionaries: '' category: 'SUnit-Kernel'! !TestSuite commentStamp: '<historical>' prior: 0! This is a Composite of Tests, either TestCases or other TestSuites. The common protocol is #run: aTestResult and the dependencies protocol! ----- Method: TestSuite class>>named: (in category 'instance creation') ----- named: aString ^self new name: aString; yourself ! ----- Method: TestSuite>>addDependentToHierachy: (in category 'dependencies') ----- addDependentToHierachy: anObject self addDependent: anObject. self tests do: [ :each | each addDependentToHierachy: anObject] ! ----- Method: TestSuite>>addTest: (in category 'accessing') ----- addTest: aTest self tests add: aTest ! ----- Method: TestSuite>>addTests: (in category 'accessing') ----- addTests: aCollection aCollection do: [:eachTest | self addTest: eachTest] ! ----- Method: TestSuite>>debug (in category 'running') ----- debug self tests do: [ : each | self changed: each. each debug ]! ----- Method: TestSuite>>defaultResources (in category 'accessing') ----- defaultResources ^self tests inject: Set new into: [:coll :testCase | coll addAll: testCase resources; yourself] ! ----- Method: TestSuite>>name (in category 'accessing') ----- name ^name ! ----- Method: TestSuite>>name: (in category 'accessing') ----- name: aString name := aString ! ----- Method: TestSuite>>removeDependentFromHierachy: (in category 'dependencies') ----- removeDependentFromHierachy: anObject self removeDependent: anObject. self tests do: [ :each | each removeDependentFromHierachy: anObject] ! ----- Method: TestSuite>>resources (in category 'accessing') ----- resources ^ resources ifNil: [resources := self defaultResources] ! ----- Method: TestSuite>>resources: (in category 'accessing') ----- resources: anObject resources := anObject ! ----- Method: TestSuite>>resultClass (in category 'private') ----- resultClass ^ TestResult.! ----- Method: TestSuite>>run (in category 'running') ----- run | result | result := self resultClass new. self resources do: [ :res | res isAvailable ifFalse: [^res signalInitializationError]]. [self run: result] ensure: [self resources do: [:each | each reset]]. ^result ! ----- Method: TestSuite>>run: (in category 'running') ----- run: aResult self tests do: [:each | self changed: each. each run: aResult]. ! ----- Method: TestSuite>>tests (in category 'accessing') ----- tests ^ tests ifNil: [tests := OrderedCollection new] ! |
Free forum by Nabble | Edit this page |