Jump to page: 1 2
Thread overview
unit-threaded v0.7.45 - now with more fluency
May 05, 2018
Atila Neves
May 05, 2018
Johannes Loher
May 07, 2018
Dechcaudron
May 08, 2018
Johannes Loher
May 08, 2018
Cym13
May 09, 2018
Cym13
May 09, 2018
bauss
May 09, 2018
Jacob Carlborg
May 08, 2018
Dechcaudron
May 09, 2018
bauss
May 05, 2018
For those not in the know, unit-threaded is an advanced testing library for D that runs tests in threads by default. It has a lot of features:

http://code.dlang.org/packages/unit-threaded

New:

* Bug fixes
* Better integration testing
* unitThreadedLight mode also runs tests in threads
* More DDoc documentation (peer pressure from Adam's site)
* Sorta kinda fluent-like asserts

On the new asserts (should and should.be are interchangeable):

    1.should == 1
    1.should.not == 2

    1.should.be in [1, 2, 3]
    4.should.not.be in [1, 2, 3]

More controversially (due to a lack of available operators to overload):

    // same as .shouldApproxEqual
    1.0.should ~ 1.0001;
    1.0.should.not ~ 2.0;

    // same as .shouldBeSameSetAs
    [1, 2, 3].should ~ [3, 2, 1];
    [1, 2, 3].should.not ~ [1, 2, 2];


I also considered adding `.should ~=`. I think it even reads better, but apparently some people don't. Let me know?

The operator overloads are completely optional.


Atila


May 05, 2018
On Saturday, 5 May 2018 at 13:28:41 UTC, Atila Neves wrote:
> For those not in the know, unit-threaded is an advanced testing library for D that runs tests in threads by default. It has a lot of features:
>
> http://code.dlang.org/packages/unit-threaded
>
> New:
>
> * Bug fixes
> * Better integration testing
> * unitThreadedLight mode also runs tests in threads
> * More DDoc documentation (peer pressure from Adam's site)
> * Sorta kinda fluent-like asserts
>
> On the new asserts (should and should.be are interchangeable):
>
>     1.should == 1
>     1.should.not == 2
>
>     1.should.be in [1, 2, 3]
>     4.should.not.be in [1, 2, 3]
>
> More controversially (due to a lack of available operators to overload):
>
>     // same as .shouldApproxEqual
>     1.0.should ~ 1.0001;
>     1.0.should.not ~ 2.0;
>
>     // same as .shouldBeSameSetAs
>     [1, 2, 3].should ~ [3, 2, 1];
>     [1, 2, 3].should.not ~ [1, 2, 2];
>
>
> I also considered adding `.should ~=`. I think it even reads better, but apparently some people don't. Let me know?
>
> The operator overloads are completely optional.
>
>
> Atila

Personally, I don't like that kind of "abuse" of operators at all. I think it looks really unusual and it kind of breaks your "flow" when reading the code. Additionally, people, who don't know about the special behaviour the operators have in this case, might get really confused. I would much prefer it, if you used a more common fluent style (like 1.0.should.be.approximately(1.0001);).

Anyways, thanks for working on this awesome project!
May 07, 2018
On Saturday, 5 May 2018 at 15:51:11 UTC, Johannes Loher wrote:
> Personally, I don't like that kind of "abuse" of operators at all. I think it looks really unusual and it kind of breaks your "flow" when reading the code. Additionally, people, who don't know about the special behaviour the operators have in this case, might get really confused. I would much prefer it, if you used a more common fluent style (like 1.0.should.be.approximately(1.0001);).
>
> Anyways, thanks for working on this awesome project!

I think I'm siding with Johannes here. Much as the overloads look nice, I don't really see the advantage over `shouldEqual`. Also, what's with `all.these.identifiers`? Any particular reason why you are more fond of them rather than of good ol' pascalCase?
May 08, 2018
On Monday, 7 May 2018 at 09:19:31 UTC, Dechcaudron wrote:
> On Saturday, 5 May 2018 at 15:51:11 UTC, Johannes Loher wrote:
>> Personally, I don't like that kind of "abuse" of operators at all. I think it looks really unusual and it kind of breaks your "flow" when reading the code. Additionally, people, who don't know about the special behaviour the operators have in this case, might get really confused. I would much prefer it, if you used a more common fluent style (like 1.0.should.be.approximately(1.0001);).
>>
>> Anyways, thanks for working on this awesome project!
>
> I think I'm siding with Johannes here. Much as the overloads look nice, I don't really see the advantage over `shouldEqual`. Also, what's with `all.these.identifiers`? Any particular reason why you are more fond of them rather than of good ol' pascalCase?
Fluent assertions have one major advantage over using pascalCase assertions: There is no ambiuguity about the order of arguments.

When using e.g. assertEquals, how do you know wheter is is supposed to be assertEquals(actual, expected), or assertEquals(expected, actual)? The first one is the only one that makes sense wirh UFCS, but it is not clear directly from the API. On top of that, some popular Frameworks (I‘m looking at you, JUnit...) do it exactly the other
way round.

With fluent assertions, you don‘t have this Problem, it is much more clear that it should be actual.should.equal(expected) and not expected.should.equal(actual), because it fits naturally in the chain of ufcs calls.

May 08, 2018
On 05/07/2018 11:57 PM, Johannes Loher wrote:
> On Monday, 7 May 2018 at 09:19:31 UTC, Dechcaudron wrote:
>> I think I'm siding with Johannes here. Much as the overloads look nice, I don't really see the advantage over `shouldEqual`. Also, what's with `all.these.identifiers`? Any particular reason why you are more fond of them rather than of good ol' pascalCase?
> Fluent assertions have one major advantage over using pascalCase assertions: There is no ambiuguity about the order of arguments.
> 
> When using e.g. assertEquals, how do you know wheter is is supposed to be assertEquals(actual, expected), or assertEquals(expected, actual)? The first one is the only one that makes sense wirh UFCS, but it is not clear directly from the API. On top of that, some popular Frameworks (I‘m looking at you, JUnit...) do it exactly the other
> way round.
> 
> With fluent assertions, you don‘t have this Problem, it is much more clear that it should be actual.should.equal(expected) and not expected.should.equal(actual), because it fits naturally in the chain of ufcs calls.
> 

I don't think that's the issue. At least, it isn't for me.

It's not a question of "assert equals" vs "should equal" (Though I am convinced by your argument on that matter).

The question is: Why "should.equal" instead of "shouldEqual"? The dot only seems there to be cute.

Not that I'm necessarily opposed to any of it (heck, I like cuteness in any sense of the word), it's just that: If the "~" thing is operator abuse, then I don't see how "should.equal", "should.not.be" etc, wouldn't fall into the same category.
May 08, 2018
On Tuesday, 8 May 2018 at 07:07:30 UTC, Nick Sabalausky (Abscissa) wrote:
> On 05/07/2018 11:57 PM, Johannes Loher wrote:
>> On Monday, 7 May 2018 at 09:19:31 UTC, Dechcaudron wrote:
>>> I think I'm siding with Johannes here. Much as the overloads look nice, I don't really see the advantage over `shouldEqual`. Also, what's with `all.these.identifiers`? Any particular reason why you are more fond of them rather than of good ol' pascalCase?
>> Fluent assertions have one major advantage over using pascalCase assertions: There is no ambiuguity about the order of arguments.
>> 
>> When using e.g. assertEquals, how do you know wheter is is supposed to be assertEquals(actual, expected), or assertEquals(expected, actual)? The first one is the only one that makes sense wirh UFCS, but it is not clear directly from the API. On top of that, some popular Frameworks (I‘m looking at you, JUnit...) do it exactly the other
>> way round.
>> 
>> With fluent assertions, you don‘t have this Problem, it is much more clear that it should be actual.should.equal(expected) and not expected.should.equal(actual), because it fits naturally in the chain of ufcs calls.
>> 
>
> I don't think that's the issue. At least, it isn't for me.
>
> It's not a question of "assert equals" vs "should equal" (Though I am convinced by your argument on that matter).
>
> The question is: Why "should.equal" instead of "shouldEqual"? The dot only seems there to be cute.
>
> Not that I'm necessarily opposed to any of it (heck, I like cuteness in any sense of the word), it's just that: If the "~" thing is operator abuse, then I don't see how "should.equal", "should.not.be" etc, wouldn't fall into the same category.

I wouldn't say it's an abuse, the dot means exactly the same thing as everywhere else in the language. I'm way less fan of overidding ~ since that doesn't have that meaning in any other context.

Without having actually used it, I like the composability over pascalCasing here, it looks like it fits nicely in a functional environment with things like aliases and partials I think, defining your own primitives naturally... Nothing one can't do with regular functions and pascalCased assertions, but it sounds like it would be way more verbose.

It also sounds like it's easier on the implementation side since you never have to define both a "shouldSomething" and "shouldNotSomething", and that means as a user I can expect less bugs and better maintainance of the library.

That said, it'll have to be field-tested to be sure.
May 08, 2018
On Tuesday, 8 May 2018 at 03:57:25 UTC, Johannes Loher wrote:
> Fluent assertions have one major advantage over using pascalCase assertions: There is no ambiuguity about the order of arguments.
>
> When using e.g. assertEquals, how do you know wheter is is supposed to be assertEquals(actual, expected), or assertEquals(expected, actual)? The first one is the only one that makes sense wirh UFCS, but it is not clear directly from the API. On top of that, some popular Frameworks (I‘m looking at you, JUnit...) do it exactly the other
> way round.
>
> With fluent assertions, you don‘t have this Problem, it is much more clear that it should be actual.should.equal(expected) and not expected.should.equal(actual), because it fits naturally in the chain of ufcs calls.

Okay, I think I see your point, although it looks to me the added verbosity and code complexity is not really worth it, provided you always use UFCS. But of course, that cannot be easily enforced I guess.
May 09, 2018
On 05/08/2018 05:05 AM, Cym13 wrote:
> 
> I wouldn't say it's an abuse, the dot means exactly the same thing as everywhere else in the language.

No, it really doesn't mean the same thing at all. Not when you look away from the unimportant implementation details and towards the big picture:

Normally, saying "x.y" denotes composition and membership: It means "y, which is a member of x". Saying "x.y" does NOT normally denote "The boundary between word 'x' and word 'y' in an english-grammared phrase".

But with things like "should.not.be", it's very much NOT a composition/membership relationship: A "be" is not really a member/property/component/etc of a "not", except in the sense that that's how the english-like DSL is internally implemented. A "should" is not really something that is composed of a "not", except in the sense that that's how the english-like DSL is internally implemented. (IF it even is implemented that way at all. I didn't look, so for all I know it might be opDispatch.)

I'm not saying that "should.not.be" OR "~" are abuses, I'm just saying whether or not they are, they're definitely both in the same category: Either they're both abuses or neither one is, because they both do the same thing: utilize use existing syntax for something other than the syntax's usual semantic meaning.

Formal "operator overloading" isn't the only way to alter (or arguably abuse) a language's normal semantics.
May 09, 2018
On Saturday, 5 May 2018 at 15:51:11 UTC, Johannes Loher wrote:
> On Saturday, 5 May 2018 at 13:28:41 UTC, Atila Neves wrote:
>> For those not in the know, unit-threaded is an advanced testing library for D that runs tests in threads by default. It has a lot of features:
>>
>> http://code.dlang.org/packages/unit-threaded
>>
>> New:
>>
>> * Bug fixes
>> * Better integration testing
>> * unitThreadedLight mode also runs tests in threads
>> * More DDoc documentation (peer pressure from Adam's site)
>> * Sorta kinda fluent-like asserts
>>
>> On the new asserts (should and should.be are interchangeable):
>>
>>     1.should == 1
>>     1.should.not == 2
>>
>>     1.should.be in [1, 2, 3]
>>     4.should.not.be in [1, 2, 3]
>>
>> More controversially (due to a lack of available operators to overload):
>>
>>     // same as .shouldApproxEqual
>>     1.0.should ~ 1.0001;
>>     1.0.should.not ~ 2.0;
>>
>>     // same as .shouldBeSameSetAs
>>     [1, 2, 3].should ~ [3, 2, 1];
>>     [1, 2, 3].should.not ~ [1, 2, 2];
>>
>>
>> I also considered adding `.should ~=`. I think it even reads better, but apparently some people don't. Let me know?
>>
>> The operator overloads are completely optional.
>>
>>
>> Atila
>
> Personally, I don't like that kind of "abuse" of operators at all. I think it looks really unusual and it kind of breaks your "flow" when reading the code.

I agree with this. If the comments weren't added, nobody reading the code would have any idea what it actually does except for whoever wrote it.


May 09, 2018
On Wednesday, 9 May 2018 at 04:40:37 UTC, Nick Sabalausky (Abscissa) wrote:
> On 05/08/2018 05:05 AM, Cym13 wrote:
>> [...]
>
> No, it really doesn't mean the same thing at all. Not when you look away from the unimportant implementation details and towards the big picture:
>
> [...]

With UFCS I find that in my code a dot means "function composition" more often than "is a member of". Maybe it's just that I like writting in a functional style, but UFCS chains are very much endorsed by the language, so I wouldn't call it a stretch.
« First   ‹ Prev
1 2