July 03, 2015
On Thursday, 2 July 2015 at 12:28:41 UTC, Dicebot wrote:
> On Wednesday, 1 July 2015 at 19:38:20 UTC, Jacob Carlborg wrote:
>> In every project I have used RSpec I have added custom matchers/assertions. Just a couple of days ago I added a custom matcher to one of my projects:
>>
>> code = code_to_file('void foo() {}')
>> code.should be_parsed_as('meta.definition.method.d')
>>
>> The point of these custom matchers/assertions are that they should make the tests (or specs in the BDD case) more readable and provide better assertion failure messages. Of course, none of these assertions are necessary, we could all just use "assert" or "shouldEqual", in the end every assertion is just a boolean condition.
>>
>> My test could instead look like this, without using a custom matcher:
>>
>> file = code_to_file('void foo() {}')
>> result = `spec/bin/gtm < "#{file.path}" Syntaxes/D.tmLanguage 2>&1`
>> line = result.split("\n").first
>> scope = 'meta.definition.method.d'
>> assert line =~ /#{Regexp.escape(scope)}/
>>
>> Which one of the two versions are more readable?
>
> Neither. But with the second one I at least have a chance to figure out what it actually tests. To understand the first one I'd need to read the code of that custom matcher.

The good thing about the first one is that you give it a name. The names tells you something about what it does, without having to understand the low-level details - but also, it gives you something to refer to in the documentation.

Moreover, it is the inevitable outcome after one has copy-and-pasted the second version 10 times.

> This is exactly the problem with all that fancy - library/app author (who by definition knows the domain well) implicitly introduces custom DSL and expects everyone (who, by definition, have very vague understanding of domain) to be able to read it as comfortably as himself.

A natural consequence of having a domain in the first place.
July 03, 2015
On 03/07/15 16:07, linkrope wrote:

> 3. 'should' seems to be obsolete
>
> Now, 'expect' should be used for expectations:
>
> http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/

As far as I know, the only reason for that is that "should" is monkey patched on every class. This can cause problems if "method_missing" is implemented. D doesn't have this problem since "should" is not monkey patched on anything. In this code "should" is implemented like a free function and UFCS is used to get the same syntax as in Ruby. If there are problems with opDispatch/alias this (the D version of method_missing) then the regular function call syntax can be used.

-- 
/Jacob Carlborg
July 10, 2015
On Thursday, 2 July 2015 at 12:22:31 UTC, Atila Neves wrote:
> On Wednesday, 1 July 2015 at 19:38:20 UTC, Jacob Carlborg wrote:
>> On 01/07/15 10:40, Atila Neves wrote:
>>
>>> [...]
>>
>> You could write "shouldBe.gt(value)".
>>
>>> [...]
>>
>> In every project I have used RSpec I have added custom matchers/assertions. Just a couple of days ago I added a custom matcher to one of my projects:
>>
>> [...]
>
> Ah, makes sense. I think I'm convinced now. The UFCS as an extension mechanism could indeed be handy.
>
> Atila

So... unconvinced again. I tried implementing it and it started getting to be a right royal pain, and then I realised that there's nothing to prevent a user from writing their own matchers right now. From your example:

    void shouldBeParsedAs(Code code, ASTNode node) {  //I don't really know what the types should be
        if(...) {
            throw new UnitTestException(...);
        }
    }

And... done. No need for a `Should` struct, no need for the complications I faced trying to use one. I think the design is as good as it can be.

Atila
July 12, 2015
On 2015-07-10 14:37, Atila Neves wrote:

> So... unconvinced again. I tried implementing it and it started getting
> to be a right royal pain, and then I realised that there's nothing to
> prevent a user from writing their own matchers right now. From your
> example:
>
>      void shouldBeParsedAs(Code code, ASTNode node) {  //I don't really
> know what the types should be
>          if(...) {
>              throw new UnitTestException(...);
>          }
>      }
>
> And... done. No need for a `Should` struct, no need for the
> complications I faced trying to use one. I think the design is as good
> as it can be.

If I compare this with RSpec. A custom matcher in RSpec would implement one method, returning a bool, to indicate if the assertion passed or not. In your example the user need to worry about throwing exceptions and which kind to throw. I consider that an implementation detail.

Also, RSpec is able to automatically infer a failure message based on the name of the matcher. Optionally the matcher can customize the failing message.

It seems like with your version you need to implement both a positive and negative version.

-- 
/Jacob Carlborg
July 13, 2015
On Sunday, 12 July 2015 at 15:15:07 UTC, Jacob Carlborg wrote:
> On 2015-07-10 14:37, Atila Neves wrote:
>
>> So... unconvinced again. I tried implementing it and it started getting
>> to be a right royal pain, and then I realised that there's nothing to
>> prevent a user from writing their own matchers right now. From your
>> example:
>>
>>      void shouldBeParsedAs(Code code, ASTNode node) {  //I don't really
>> know what the types should be
>>          if(...) {
>>              throw new UnitTestException(...);
>>          }
>>      }
>>
>> And... done. No need for a `Should` struct, no need for the
>> complications I faced trying to use one. I think the design is as good
>> as it can be.
>
> If I compare this with RSpec. A custom matcher in RSpec would implement one method, returning a bool, to indicate if the assertion passed or not. In your example the user need to worry about throwing exceptions and which kind to throw. I consider that an implementation detail.
>
> Also, RSpec is able to automatically infer a failure message based on the name of the matcher. Optionally the matcher can customize the failing message.
>
> It seems like with your version you need to implement both a positive and negative version.

There's a reason for that and I'm curious as to how RSpec handles it. If it were just a matter of pairing up assertions for the two boolean values of a condition that'd be easy. But the formatting of the error message is anything but. `shouldEqual` and `shouldNotEqual` have very different outputs even if what causes an exception to be thrown is just a check on the opposite condition.

For the same reason, a user wanting to extend the framework has to format their own error messages, which means just defining a predicate isn't enough.

If I'd seen any more duplication I'd've removed it, but the different positive and negative versions of the `should` assertions are due to the very asymmetrical error messages. If there's a better way of doing it I'd love to find out.

Atila
1 2 3 4
Next ›   Last »