[squeak-dev] The Inbox: SUnit-ct.127.mcz

Thiede, Christoph Christoph.Thiede at student.hpi.uni-potsdam.de
Sat Apr 11 13:45:31 UTC 2020


Hi all, thanks for your feedback! :-)


Originally, I wrote these assertions for testing the refactored inspectors<http://forum.world.st/Refactoring-Inspectors-td5111788.html#a5111916>, only. Marcel suggested me to push them up into TestCase and in general, I liked the idea because it would save every new specific test suite from implementing the same stuff again whenever desired. On the other hand, I share yours (Chris) fears that this approach could turn TestCase into a god class for everything that can be asserted in any way. Analogously, you could introduce #assert:lowerThan:, #assert:includes: and much more domain-specific assertion. I don't know where to draw the line.


Other test frameworks such as python's unittest or XUnit for .NET declare a lot of domain-specific assertions (for system domains such as regex, collections). Is this a desirable goal?

On the one hand, it maximizes the convenience of the test developer in terms of writing or reading the test code or getting comprehensive assertion failures.

On the other hand, this approach can cause a lot of duplication what is quite the opposite of Smalltalk's minimalism which I do appreciate very much and always strive to preserve.


@Jakob: Oh, that compatibility aspect is good to know. I suppose I now understand the sense of the SUnitExtensions separation. I suppose #assert:matches: should belong into the "extensions" category of TestCase, and the tests into SUnitExtensionsTest (provided that we wanted the feature at all, see above)?


Best,

Christoph

________________________________
Von: Squeak-dev <squeak-dev-bounces at lists.squeakfoundation.org> im Auftrag von Chris Muller <asqueaker at gmail.com>
Gesendet: Samstag, 11. April 2020 03:56:36
An: The general-purpose Squeak developers list
Betreff: Re: [squeak-dev] The Inbox: SUnit-ct.127.mcz

I share Jakob's sentiments on this, and would wonder whether this particular kind of domain-specific matching is an appropriate responsibility for SUnit.  Currently, it's 100% client responsibility to calculate assertions for SUnit.  Blending this responsibility into SUnit means it could drift over time, causing tests that once passed to no longer passed (if they depended on these methods).

On Fri, Apr 10, 2020 at 4:30 AM Jakob Reschke <forums.jakob at resfarm.de<mailto:forums.jakob at resfarm.de>> wrote:
Please be aware that the basic SUnit is not specific to Squeak and
enlarging its interface makes it even more unlikely that the written
test cases will be portable.

http://sunit.sourceforge.net/

Although I am afraid that compatibility might not maintained any more already.
Nevertheless one could at least put the additional methods in an
extensions package, which could as well be in Squeak Trunk.

Am Do., 9. Apr. 2020 um 14:23 Uhr schrieb <commits at source.squeak.org<mailto:commits at source.squeak.org>>:
>
> Christoph Thiede uploaded a new version of SUnit to project The Inbox:
> http://source.squeak.org/inbox/SUnit-ct.127.mcz
>
> ==================== Summary ====================
>
> Name: SUnit-ct.127
> Author: ct
> Time: 9 April 2020, 2:22:49.769949 pm
> UUID: bf5be456-fbd7-e343-9158-da59c75fa05d
> Ancestors: SUnit-ct.126
>
> Adds support for string pattern assertions (#assert:matches:[description:] and #deny:matches:[description:]). Also tests these selectors in SUnitTest.
>
> TestCase new assert: 'Sq*k' matches: 'Squeak'.
> TestCase new assert: 'Sq\w+k' asRegex matches: 'Squeak'.
> TestCase new deny: '.*\d' asRegex matches: 'Squeak123' description: 'This one will fail'.
>
> Depends indeed on SUnit-ct.126.
>
> =============== Diff against SUnit-ct.126 ===============
>
> Item was added:
> + ----- Method: SUnitTest>>testAssertMatches (in category 'tests') -----
> + testAssertMatches
> +
> +       | pattern positive negative notAString |
> +       pattern := 'f*'.
> +       positive := 'foo'.
> +       negative := 'bar'.
> +       notAString := Object new.
> +
> +       self shouldnt: [self assert: pattern matches: positive] raise: TestFailure.
> +
> +       self should: [self assert: pattern matches: negative] raise: TestFailure.
> +       [self assert: pattern matches: negative]
> +               on: TestFailure do: [:ex |
> +                       | error |
> +                       error := ex messageText.
> +                       self
> +                               assert: (error includesSubstring: pattern)
> +                               description: 'Error message doesn''t include the expected pattern'.
> +                       self
> +                               assert: (error includesSubstring: negative)
> +                               description: 'Error message doesn''t include the actual value'].
> +
> +       self should: [self assert: pattern matches: notAString] raise: TestFailure.
> +       [self assert: pattern matches: notAString]
> +               on: TestFailure do: [:ex |
> +                       | error |
> +                       error := ex messageText.
> +                       self
> +                               assert: (error includesSubstring: 'string')
> +                               description: 'Error message doesn''t say that we''re passing a non-string object here'.
> +                       self
> +                               assert: (error includesSubstring: pattern)
> +                               description: 'Error message doesn''t include the expected pattern'.
> +                       self
> +                               assert: (error includesSubstring: notAString asString)
> +                               description: 'Error message doesn''t include the actual value'].!
>
> Item was added:
> + ----- Method: SUnitTest>>testAssertMatchesDescription (in category 'tests') -----
> + testAssertMatchesDescription
> +
> +       | pattern positive negative notAString |
> +       pattern := 'f*'.
> +       positive := 'foo'.
> +       negative := 'bar'.
> +       notAString := Object new.
> +
> +       self shouldnt: [self assert: pattern matches: positive description: ['A description' , 42]] raise: TestFailure.
> +
> +       self should: [self assert: pattern matches: negative description: ['A description' , 42]] raise: TestFailure.
> +       [self assert: pattern matches: negative description: ['A description' , 42]]
> +               on: TestFailure do: [:ex |
> +                       | error |
> +                       error := ex messageText.
> +                       self
> +                               assert: (error includesSubstring: 'A description' , 42)
> +                               description: 'Error message doesn''t give you the description'].
> +
> +       self should: [self assert: pattern matches: notAString description: ['A description' , 42]] raise: TestFailure.
> +       [self assert: pattern matches: notAString description: ['A description' , 42]]
> +               on: TestFailure do: [:ex |
> +                       | error |
> +                       error := ex messageText.
> +                       self
> +                               assert: (error includesSubstring: 'string')
> +                               description: 'Error message doesn''t say that we''re passing a non-string object here'.
> +                       self
> +                               assert: (error includesSubstring: 'A description' , 42)
> +                               description: 'Error message doesn''t give you the description'].!
>
> Item was added:
> + ----- Method: SUnitTest>>testAssertMatchesRegex (in category 'tests') -----
> + testAssertMatchesRegex
> +
> +       | pattern positive negative notAString |
> +       pattern := 'fo+' asRegex.
> +       positive := 'foo'.
> +       negative := 'f'.
> +       notAString := Object new.
> +
> +       self shouldnt: [self assert: pattern matches: positive] raise: TestFailure.
> +
> +       self should: [self assert: pattern matches: negative] raise: TestFailure.
> +       [self assert: pattern matches: negative]
> +               on: TestFailure do: [:ex |
> +                       | error |
> +                       error := ex messageText.
> +                       self
> +                               assert: (error includesSubstring: pattern asString)
> +                               description: 'Error message doesn''t include the expected regex pattern'.
> +                       self
> +                               assert: (error includesSubstring: negative)
> +                               description: 'Error message doesn''t include the actual value'].
> +
> +       self should: [self assert: pattern matches: notAString] raise: TestFailure.
> +       [self assert: pattern matches: notAString]
> +               on: TestFailure do: [:ex |
> +                       | error |
> +                       error := ex messageText.
> +                       self
> +                               assert: (error includesSubstring: 'string')
> +                               description: 'Error message doesn''t say that we''re passing a non-string object here'.
> +                       self
> +                               assert: (error includesSubstring: pattern asString)
> +                               description: 'Error message doesn''t include the expected regex pattern'.
> +                       self
> +                               assert: (error includesSubstring: notAString asString)
> +                               description: 'Error message doesn''t include the actual value'].!
>
> Item was added:
> + ----- Method: SUnitTest>>testDenyMatches (in category 'tests') -----
> + testDenyMatches
> +
> +       | pattern positive negative notAString |
> +       pattern := 'f*'.
> +       positive := 'foo'.
> +       negative := 'bar'.
> +       notAString := Object new.
> +
> +       self shouldnt: [self deny: pattern matches: negative] raise: TestFailure.
> +
> +       self should: [self deny: pattern matches: positive] raise: TestFailure.
> +       [self deny: pattern matches: positive]
> +               on: TestFailure do: [:ex |
> +                       | error |
> +                       error := ex messageText.
> +                       self
> +                               assert: (error includesSubstring: pattern)
> +                               description: 'Error message doesn''t include the expected pattern'.
> +                       self
> +                               assert: (error includesSubstring: positive)
> +                               description: 'Error message doesn''t include the actual value'].
> +
> +       self should: [self deny: pattern matches: notAString] raise: TestFailure.
> +       [self deny: pattern matches: notAString]
> +               on: TestFailure do: [:ex |
> +                       | error |
> +                       error := ex messageText.
> +                       self
> +                               assert: (error includesSubstring: 'string')
> +                               description: 'Error message doesn''t say that we''re passing a non-string object here'.
> +                       self
> +                               assert: (error includesSubstring: pattern)
> +                               description: 'Error message doesn''t include the expected pattern'.
> +                       self
> +                               assert: (error includesSubstring: notAString asString)
> +                               description: 'Error message doesn''t include the actual value'].!
>
> Item was added:
> + ----- Method: SUnitTest>>testDenyMatchesDescription (in category 'tests') -----
> + testDenyMatchesDescription
> +
> +       | pattern positive negative notAString |
> +       pattern := 'f*'.
> +       positive := 'foo'.
> +       negative := 'bar'.
> +       notAString := Object new.
> +
> +       self shouldnt: [self deny: pattern matches: negative description: ['A description' , 42]] raise: TestFailure.
> +
> +       self should: [self deny: pattern matches: positive description: ['A description' , 42]] raise: TestFailure.
> +       [self deny: pattern matches: positive description: ['A description' , 42]]
> +               on: TestFailure do: [:ex |
> +                       | error |
> +                       error := ex messageText.
> +                       self
> +                               assert: (error includesSubstring: 'A description' , 42)
> +                               description: 'Error message doesn''t give you the description'].
> +
> +       self should: [self deny: pattern matches: notAString description: ['A description' , 42]] raise: TestFailure.
> +       [self deny: pattern matches: notAString description: ['A description' , 42]]
> +               on: TestFailure do: [:ex |
> +                       | error |
> +                       error := ex messageText.
> +                       self
> +                               assert: (error includesSubstring: 'string')
> +                               description: 'Error message doesn''t say that we''re passing a non-string object here'.
> +                       self
> +                               assert: (error includesSubstring: 'A description' , 42)
> +                               description: 'Error message doesn''t give you the description'].!
>
> Item was added:
> + ----- Method: SUnitTest>>testDenyMatchesRegex (in category 'tests') -----
> + testDenyMatchesRegex
> +
> +       | pattern positive negative notAString |
> +       pattern := 'fo+' asRegex.
> +       positive := 'foo'.
> +       negative := 'f'.
> +       notAString := Object new.
> +
> +       self shouldnt: [self deny: pattern matches: negative] raise: TestFailure.
> +
> +       self should: [self deny: pattern matches: positive] raise: TestFailure.
> +       [self deny: pattern matches: positive]
> +               on: TestFailure do: [:ex |
> +                       | error |
> +                       error := ex messageText.
> +                       self
> +                               assert: (error includesSubstring: pattern asString)
> +                               description: 'Error message doesn''t include the expected regex pattern'.
> +                       self
> +                               assert: (error includesSubstring: negative)
> +                               description: 'Error message doesn''t include the actual value'].
> +
> +       self should: [self deny: pattern matches: notAString] raise: TestFailure.
> +       [self deny: pattern matches: notAString]
> +               on: TestFailure do: [:ex |
> +                       | error |
> +                       error := ex messageText.
> +                       self
> +                               assert: (error includesSubstring: 'string')
> +                               description: 'Error message doesn''t say that we''re passing a non-string object here'.
> +                       self
> +                               assert: (error includesSubstring: pattern asString)
> +                               description: 'Error message doesn''t include the expected regex pattern'.
> +                       self
> +                               assert: (error includesSubstring: notAString asString)
> +                               description: 'Error message doesn''t include the actual value'].!
>
> Item was added:
> + ----- Method: TestCase>>assert:matches: (in category 'accessing') -----
> + assert: pattern matches: actual
> +
> +       ^ self
> +               assert: pattern
> +               matches: actual
> +               description: nil!
>
> Item was added:
> + ----- Method: TestCase>>assert:matches:description: (in category 'accessing') -----
> + assert: pattern matches: actual description: aStringOrBlock
> +
> +       self
> +               assert: [actual isString or: [actual isText]]
> +               description: [self
> +                       description: aStringOrBlock
> +                       with: (self comparingStringBetweenPattern: pattern andNonTextual: actual)].
> +       self
> +               assert: [self doesPattern: pattern match: actual]
> +               description: [self
> +                       description: aStringOrBlock
> +                       with: (self comparingStringBetweenPattern: pattern and: actual)].!
>
> Item was added:
> + ----- Method: TestCase>>comparingStringBetweenPattern:and: (in category 'private') -----
> + comparingStringBetweenPattern: pattern and: actual
> +
> +       ^ 'Expected pattern {1} does not match actual {2}.' translated
> +               format: {
> +                       pattern.
> +                       actual }!
>
> Item was added:
> + ----- Method: TestCase>>comparingStringBetweenPattern:andNonTextual: (in category 'private') -----
> + comparingStringBetweenPattern: pattern andNonTextual: actual
> +
> +       ^ 'Expected something that matches {1} but actual {2} is neither string nor text.' translated
> +               format: {
> +                       pattern.
> +                       actual }!
>
> Item was added:
> + ----- Method: TestCase>>comparingStringBetweenUnexpectedPattern:and: (in category 'private') -----
> + comparingStringBetweenUnexpectedPattern: pattern and: actual
> +
> +       ^ 'Unexpected pattern {1} does match actual {2}.' translated
> +               format: {
> +                       pattern.
> +                       actual }!
>
> Item was added:
> + ----- Method: TestCase>>comparingStringBetweenUnexpectedPattern:andNonTextual: (in category 'private') -----
> + comparingStringBetweenUnexpectedPattern: pattern andNonTextual: actual
> +
> +       ^ 'Expected something that does not match {1} but actual {2} is neither string nor text.' translated
> +               format: {
> +                       pattern.
> +                       actual }!
>
> Item was added:
> + ----- Method: TestCase>>deny:matches: (in category 'accessing') -----
> + deny: pattern matches: actual
> +
> +       ^ self
> +               deny: pattern
> +               matches: actual
> +               description: nil!
>
> Item was added:
> + ----- Method: TestCase>>deny:matches:description: (in category 'accessing') -----
> + deny: pattern matches: actual description: aStringOrBlock
> +
> +       self
> +               assert: [actual isString or: [actual isText]]
> +               description: [self
> +                       description: aStringOrBlock
> +                       with: (self comparingStringBetweenUnexpectedPattern: pattern andNonTextual: actual)].
> +       self
> +               deny: [self doesPattern: pattern match: actual]
> +               description: [self
> +                       description: aStringOrBlock
> +                       with: (self comparingStringBetweenUnexpectedPattern: pattern and: actual)].!
>
> Item was added:
> + ----- Method: TestCase>>doesPattern:match: (in category 'private') -----
> + doesPattern: pattern match: stringOrText
> +
> +       ^ (pattern respondsTo: #matches:)
> +               ifTrue: [pattern matches: stringOrText]
> +               ifFalse: [pattern match: stringOrText]!
>
>


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20200411/67724409/attachment.html>


More information about the Squeak-dev mailing list