[Pharo-users] TestAsserter>>assertCollection:hasSameElements:

Peter Uhnák i.uhnak at gmail.com
Mon Oct 26 18:53:38 EDT 2015


On Mon, Oct 26, 2015 at 8:27 AM, jtuchel at objektfabrik.de <
jtuchel at objektfabrik.de> wrote:

> Am 25.10.15 um 16:33 schrieb Peter Uhnák:
>
> > assert:equals:  it's just more typing than #= with no additional outcome
>>
>
> I also disagree, but that may be also because maybe we write tests for
> different purpse.
> If you write tests just to test your code, then whatever... I don't do
> that so I can't comment on that.
>
> However if you do TDD, then tests are to provide feedback, and from that
> perspective you want to see immediately what is the difference. If I see
> that the assertion failed I have to start digging to find out what is the
> difference, which is extra work and bad from feedback perspective. If I
> instead immediately see what I need to see it allows me to faster deduce
> the source of the problem and resolve it.
>
> I'm sorry, but what you are saying doesn't make any sense. Even if I
> "only" want to test code (which is exactly what you do in TDD, btw.), I
> need good feedback.
>

Well, that was a bit of generalization on my part. The point was, that many
people write tests as an afterthought... which means they have different
means of getting feedback from the system (e.g. logging, running manually
the code, etc.). In such situation they often end up testing already mostly
working code, and thus the feedback from the tests is not as important,
because you end up less digging up problems (since large portion were found
and resolved during manual testing).


> We could think about subclassing TestFailure and a way to hand information
> to the TestFailure so that a nice String can be produced. Like a method
> like cull: that adds arguments' printString representation into the failure
> description.
>

You mean #assert:description: ? Because we already have that.


> Please step back for a second and think again: these are two very
> different things. The job of an Assertion is to make a problem visible. The
> representation of the problem is something else, even if these are closely
> related. This is object thinking lesson #2 or so.
>

Object thinking lesson #3 tells me that I should not care about what is
going on behind the curtains. And while I could explicitly separate the
two, if I do it all the time I don't see what's bad about having a
convenience method. (And by looking at Object or String protocol, Pharo is
a lot about having convenience over engineering rigidness).

But: adding more and more misnamed and misleading assertion methods makes
> the use of SUnit frustrating and will make it obsolete over time. If I have
> to hunt for design problems in SUnit because it assumes something to be
> wrong even though my understanding of waht I tested is different, I lose
> way more time than I am ready to accept. This doesn't happen to me often.
> If finding that I misunderstood an assertion method means I lost a few
> hours, the best thing that may happen is that I never use that method
> again. In the worst case, I decide I think SUnit is useless for me. That
> would be really bad, don't you think?
>

I am not sure if we are talking about the same SUnit. Sure, there are 32
methods in the "asserting" protocol, however most of them are either
opposites of one another "#assert: vs #deny:", or they provide some
customization such has "#assert:description:", "#should:raise:" ... so if I
count only meaningfully different methods the number 7 (not to mention that
some of the methods are not even used). But if you have trouble
understanding the purpose of seven methods, then the problem is on your
end, and don't blame SUnit for it.


>
>
>  > assertCollection:hasSameElements:
>
>> > So, let's start by asking what the question really means. Does it mean
>> that one collection is a subset of the other? What about ordering then?
>> Does it mean both contain the same elements at the same position or just
>> the fact that if they both were Sets contained the exact same elements. The
>> question itself is not exact, so how could an answer possibly be?
>>
>
> There is no question about this method, since this is implemented in code
> there is nothing ambiguous. This method effectively converts both arguments
> to sets and compares them like that.
>
>
> Sorry to say that, but this is ambiguity by design: you define
> hasSameElements: as "both result in the same Set". So the name of this
> assertion method is a great example of bad naming, IMO.
>

Yes, the naming is confusing. My point was, that instead of philosophizing
about the meaning you can look at the code. Of course if you use the method
for the first time (like I did), you will get burned by it (as I did).


> The question is whether such thing is useful for non-sets, and there are
> definitely cases where such assertion is not appropriate (when you want to
> ensure that there are specific items or specific positions), that's why I
> suggested asserts specifically for that.
>
> This is just nonsense. You name a method after a general collection class
> and try to tell me that it doesn't matter that it is only suitable for Sets
> and that is okay?
>

Nono, I am not saying that the name is good, quite the opposite. I am
asking whether that method makes sense for non-sets. Because if it doesn't,
then maybe we could rename it.
In fact in Pharo itself nobody even uses this method (the only sender is
TabManagerModelTest, where the use is NOT appropriate).



> self assert: result asOrderedCollection asSortedCollection equals: (1 to:
>> 10) asOrderedCollection
>>
>
> This is what I usually do now (although I convert to Array, not
> OrderedCollection, because the expected one is usually created by hand with
> #() or {} ).
>
> I don't really care. If what you try t say is that the testing code can be
> ugly and long, then I agree. If you need tests like this very often and
> want something to make this easier, I understand and agree that some
> additions to SUnit can be helpful. But the way this has been tried so far
> seems completely wrong to me.
>

How would you test it then? Some problem domains deal with certain kind of
problems more than others and thus benefit more from appropriate assertions.


>
> > Just a few weeks ago, we discussed something similar about the equality
>> of two Collections. Endless discussions where people try convince others
>> that their definition of equality and/or sameness is correct with no
>> outcome.
>>
>
> I don't see a problem with that because collections truly can have
> different equalities based on the context and their purpose. And while you
> can call this rat poison, it effectively tells what kind of behavior you
> expect from the collections, which seems ok.
>
> So what, again, was the point of naming a method after a general
> Collection class and use a question that is very unspecific? A Collection
> has the same elements as another does not necessarily mean they both result
> in the same set. Can we agree on that? All the question asks if all
> Elements in Collection A can also be found in Collection B. The method name
> states nothing more than that.
>

We agree that the method is badly named. (However what equality of two
Collections means is context-dependent.)


> My point here is that a general purpose framework like SUnit should be
> free of such debatable things. SUnit has to be reliable and understandable.
> There is nothing wrong with providing some "plugins" for problems like
> Collections that make life easier.
> It would be desirable to have more control over SUnit's feedback with
> little typing.
>

Well but we need a way to provide context for the assertion. If I could
type less then I would be happier user, however currently I don't see a way
how to make it more general (so I don't need to type) and more precise (it
still understands context) at the same time.
So going back to your earlier suggestion with the class... you imagine
something like this?
self assert: a equals: b strategy:
CollectionHasExactlyTheSameElementsAsAnotherAtTheSamePosition

where the method would have both the definition of the assertion and a way
to nicely display it? (which could be of course delegated to other parties
via composition, or maybe the test assertion could specify both
independently)

So my question is --- how to compare collections irrespective of type, and
>> possibly of order?
>>
>> A) always convert the actual collection toanArray
>>
>> I don't think it is a good idea to provide tests fro general Collections
> that first convert it to some specialized Collection class. There may be
> nothing wrong with doing so, but it always depends on what exactly you want
> to test for. If converting to an Array is part of that test, the test is
> specialized and not for Collections in general.
> Seems to be an indication that your test is not a general Test on
> Collections...
>

the purpose of the conversion was to have same type of both compared sides,
because I care about the content, not the wrapper (comparing
OrderedCollection to Array will always fail even if they have the same
elements)

C) extend TAssertable with new methods like
>>
>> #assertElementsOf: actualCollection equals: expectedCollection
>> #assertUnorderedElementsOf: actualCollection equals: expectedCollection
>>
>> These names (I know, they are just examples, so I don't pick on them
> specifically) are always open for interpretation.
>

The naming was just an example (first thing that came to my mind). Maybe we
could come up with a clear name.

>
> C.a) directly in Pharo/SUnit
>>
> No. For several reasons:
> * The whole discussione we're having on this
> * SUnit is a framework that is cross-platform. You can never be completely
> sure that a certain method on a Collection class which is not in the ANSI
> standard gives you the same results on another Smalltalk
>

Agreed.

> C.b) in independend SUnit-Extensions repository/project
>>
> A much better approach. But then we have a portability problem if things
> like extensions and method overrides come into play. So this requires
> architectural changes in SUnit to enable a plugin mechanism. That, btw,
> would be a great thing!
>
> C.c) just in my project
>>
> This should surely be a starting point to stabilize things. If we had
> plugins, it would be easy to publish your stuf as plugin at any time.
>
>
>> D) stop discussing non-problems
>>
> If you mean others think you should just shut up and you should just do it
> for yourself, then I think it is not a good option. I am quite sure your
> question shows that there is a problem with SUnit. Be it with Collections
> or any other area. SUnit started as something quick and dirty and thus is
> not perfect for many situations. We should look for patterns and solutions.
> I would definitely disagree if you suggest people might think your
> questions are a non-problem!
>


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Now to get somewhere, I think the main points emerging here are:

1. #assertCollection:hasSameElements: is a bad name, because it treats
arguments as sets, not generic collections

it could be renamed or removed (no code in Pharo itself uses it (only Spec,
but the use there is wrong))

2. Providing selectors such as #assertCollection:equals: and similar just
to get different description may not be the best idea, which leads to point
3

3. An easy way to extend printing/assertions/plugins; but what would that
look like?

Maybe
#assert: a = b description: [ Diff collectionDiffBetween: a and: b ]
or
#assert: a equals: b strategy:
CollectionHasExactlyTheSameElementsAsAnotherAtTheSamePosition
or
something else...


Peter
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.pharo.org/pipermail/pharo-users_lists.pharo.org/attachments/20151026/d6a147e6/attachment.html>


More information about the Pharo-users mailing list