bearophile wrote:
Walter Bright:

Experience has led me to believe that unit tests are extremely valuable, but I 
rarely see them used - even by professionals.<

In languages with dynamic typing (Python, Ruby, etc) they are used quite often, 
partially to replace errors that the static typing catches, and partially for 
other purposes (but after writing about 110.000 lines of D code I have seen 
that unit tests result very useful in D code too).
In dynamic languages they have even invented a programming style (TDD, 
Test-Driven Development) that is strictly based on unit tests: you write a unit 
test first, see it fail, you fix the code to make it pass, you add another unit 
test, you add a little more code, you see it fail, etc etc. I know it sounds a 
little crazy, but if you use dynamic languages to write certain classes of 
programs (surely it's not fit for every kind of code) it seem to work well 
enough (for some kinds of programmers, I presume).


I wanted to make them so easy to use in D that it would hook people in. That's why 
they are the way they are - super simple, next to nothing to learn, and they 
work.<

I understand. The profilers you are talking about push too much complexity to the final 
user. But ergonomics shows there are other possible designs for the interfaces of tools: 
sometimes you can push some more complexity into the product even if its interface is 
kept simple enough, making it flexible only where it more counts. So I think there are 
"few things" that can be added to the current unit test system that can 
increase its usefulness and make it more handy while keeping a simple user interface.

It's not easy to find and list such few things, I can try list something:

1) I'd like a way to state that an expression throws one or more specified 
exception(s), at runtime, for example:
Throws!(ArgumentException)(foo("hello", -5));
It also has to print that line number of the caller.
I have created something similar, but it's quite less nice:
assert( Throws!(ArgumentException)(foo("hello", -5)) );
See my Throws!() here:
http://www.fantascienza.net/leonardo/so/dlibs/func.html

For what it's worth, dunit supports this:

tests["no expected exception"] = {};
tests["fails if it doesn't throw"] = expectedException!(AssertError) = { assert(false); };

I was attempting to channel downs when I came up with this syntax.

2) The same at compile time. I think it's impossible to do currently:
static Throws!(AssertError)(foo(5, -5));

3) I need ways to unittest a specified module only. And I'd like to be able to do it even 
if the main is missing. Having a compiler-managed "mainmodule" boolean constant 
that is true only in the main module may help.

Dunit also supports unittesting a single module, but since it replaces main, you can't do without it. That said, I'm looking for workarounds, such as outputting a module sufficient to compile and run tests in the given paths.

4) I'd like to unittest nested functions too.

That's not going to be easy.

5) Few reflective capabilities can be added to D to help the handy creation of 
an external unittest system, for the people that need something quite more 
refined and complex.

d2 will get some improvements that I really would like for dunit. Runtime reflection to get a callable list of the methods on a class is a big one -- the current syntax is a hack. But that won't be sufficient to move to an Nunit/Junit style syntax; you won't get filters (parameterized tests, expected exceptions, and the like).

The really big thing after runtime reflection is user-defined metadata -- attributes or annotations, in C# or Java. User-defined metadata has a lot of other use cases, so I'm hoping this makes it into the language within a reasonable amount of time.

--------------------------

I have already given two times links to the wonderful doctest system of Python, 
but it seems no one has read it, I have seen no one comment on it. So I try a 
third time, this time I explain a little more.

Note that doctests are unfit for the current D language, but if D gains some 
runtime capabilities (like I have seen shown here two times), then its 
phylosophy may become usable.

Note that I am not talking about Test-Driven Development here, this is "normal" 
way of coding.


This is a little useful Python function that returns true if the given iterable 
contains items that are all equal. If given an optional mapping function is 
used to transform items before comparing them:

This is interesting. It's not as flexible as dunit or D's unittest blocks -- it'll complain about any user-visible changes to a function. It also looks like it'd be annoying to use, say, mock objects with it.

I would have no use for doctests, but I think it's a neat hack.

Reply via email to