www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.announce - DUnit - class MyTest { mixin TestMixin; void testMethod1() {} void

reply "Juan Manuel Cabo" <juanmanuel.cabo gmail.com> writes:
People of the D world.. I give you DUnit (not to be confused with 
an old
tango DUnit, this one is for >= D2.057, and doesn't really 
require phobos or tango (just you version the few writeln's of 
the runner, and maybe
something else)).

       https://github.com/jmcabo/dunit

I've been developing it for the past few weeks, and since I saw a 
post of another unit testing framework just a few minutes ago, I 
thought I'd rush it to github.

Soooo, here is how you define a test:


import dunit;

class Something {
     mixin TestMixin;

     void testOne() {
         assert(1 == 1, "this works");
     }

     void testTwo() {
         assertEquals(1, 2/2);
         assertEquals("a string", "a"~" string");
     }
}

.. and that's all there is to it. Put the mixin TestMixin, and 
name your tests
starting with 'test'. The results output shows all of them even 
if some fail, and... guess what, it tells you the name of the 
unit tests that failed!! isn't this awesome!! (all thanks to 
mixins, recursive template declarations, __traits, and a little 
bit of CTFE)... isn't D like, so incredibly awesome or what!?!?

There is absolutely no overhead in registering the tests for the 
test runner.. its all at compile time!

Your tests are inherited through derived classes, and can be 
private in the unit test class (they will still run).


I made two test runners:

     * One that shows the results in java style (but WITH COLORS!! 
(fineprint: colors only on unix console, windows console is 
colorless for now)

     * Another one more verbose that shows the tree of tests as it 
runs them.

It is very easy to make your own.


This is all BOOST licenced, so please tweak it away!


FINEPRINT yes shouting fineprint ;-) haha:
THIS IS NOT A unitest{} REPLACEMENT, JUST AN ITCH EVERY OOP 
PEOPLE WANTED TO SCRATCH: named, easy, xUnit style unit tests.. 
AND NOW YOU'VE GOT THEM.
Feb 19 2012
next sibling parent reply "Juan Manuel Cabo" <juanmanuel.cabo gmail.com> writes:
Unit testing framework ('dunit')

Allows to define unittests simply as methods which names start
with 'test'.
The only thing necessary to create a unit test class, is to
declare the mixin TestMixin inside the class. This will register
the class and its test methods for the test runner.

License:   <a href="http://www.boost.org/LICENSE_1_0.txt">Boost 
License 1.0</a>.
Authors:   Juan Manuel Cabo
Version:   0.3
Source:    dunit.d
Last update: 2012-02-19

          Copyright Juan Manuel Cabo 2012.
Distributed under the Boost Software License, Version 1.0.
    (See accompanying file LICENSE_1_0.txt or copy at
          http://www.boost.org/LICENSE_1_0.txt)
---------------------------------------------------------------------------------

module ExampleTests;
import std.stdio, std.string;
import dunit;


//Minimal example:
class ATestClass() {
     mixin TestMixin;

     void testExample() {
         assertEquals("bla", "b"~"la");
     }
}


/**
  * Look!! no test base class needed!!
  */
class AbcTest {
     //This declaration here is the only thing needed to mark a 
class as a unit test class.
     mixin TestMixin;

     //Variable members that start with 'test' are allowed.
     public int testN = 3;
     public int testM = 4;

     //Any method whose name starts with 'test' is run as a unit 
test:
     //(NOTE: this is bound at compile time, there is no overhead).
     public void test1() {
         assert(true);
     }

     public void test2() {
         //You can use D's assert() function:
         assert(1 == 2 / 2);
         //Or dunit convenience asserts (just edit dunit.d to add 
more):
         assertEquals(1, 2/2);
         //The expected and actual values will be shown in the 
output:
         assertEquals("my string looks dazzling", "my dtring looks 
sazzling");
     }

     //Test methods with default arguments work, as long as they 
can
     //be called without arguments, ie: as testDefaultArguments() 
for instance:
     public void testDefaultArguments(int a=4, int b=3) {
     }

     //Even if the method is private to the unit test class, it is 
still run.
     private void test5(int a=4) {
     }

     //This test was disabled just by adding an underscore to the 
name:
     public void _testAnother() {
         assert(false, "fails");
     }

     //Optional inicialization and de-initialization.
     //  setUp() and tearDown() are called around each individual 
test.
     //  setUpClass() and tearDownClass() are called once around 
the whole unit test.
     public void setUp() {
     }
     public void tearDown() {
     }
     public void setUpClass() {
     }
     public void tearDownClass() {
     }
}


class DerivedTest : AbcTest {
     mixin TestMixin;

     //Base class tests will be run!!!!!!
     //You can for instance override setUpClass() and change the 
target implementation
     //of a family of classes that you are testing.
}


version = DUnit;

version(DUnit) {

     //-All you need to run the tests, is to declare
     //
     //      mixin DUnitMain.
     //
     //-You can alternatively call
     //
     //      dunit.runTests_Progress();      for java style 
results output (SHOWS COLORS IF IN UNIX !!!)
     // or   dunit.runTests_Tree();          for a more verbose 
output
     //
     //from your main function.

     //mixin DUnitMain;
     void main() {dunit.runTests_Tree();}

} else {
     int main (string[] args) {
         writeln("production");
     }
}


/*

Run this file with (works in Windows/Linux):


     dmd exampleTests.d dunit.d
     ./exampleTests


The output will be (java style):


     ..F....F..
     There were 2 failures:
     1) 
test2(AbcTest)core.exception.AssertError exampleTests.d(60): 
Expected: 'my string looks dazzling', but was: 'my dtring looks 
sazzling'
     2) 
test2(DerivedTest)core.exception.AssertError exampleTests.d(60): 
Expected: 'my string looks dazzling', but was: 'my dtring looks 
sazzling'

     FAILURES!!!
     Tests run: 8,  Failures: 2,  Errors: 0


If you use the more verbose method dunit.runTests_Tree(), then 
the output is:


     Unit tests:
         AbcTest
             OK: test1()
             FAILED: test2(): 
core.exception.AssertError exampleTests.d(60): Expected: 'my 
string looks dazzling', but was: 'my dtring looks sazzling'
             OK: testDefaultArguments()
             OK: test5()
         DerivedTest
             OK: test1()
             FAILED: test2(): 
core.exception.AssertError exampleTests.d(60): Expected: 'my 
string looks dazzling', but was: 'my dtring looks sazzling'
             OK: testDefaultArguments()
             OK: test5()

HAVE FUN!

*/
Feb 19 2012
parent reply Juan Manuel Cabo <juanmanuel.cabo gmail.com> writes:
I thought I could do a better effort to describe why DUnit is so extraordinary,
for a native language, especially for those unfamiliar with xUnit frameworks
or TDD. So here it goes:


*What is a unit test*

Unit tests, ideally, test a specific functionality in isolation, so that
if the test fails, you can assume that it's because the functionality
under test, and only that functionality, is broken.

Testing a program or system is complex. This is not the only kind of test
that should be done on a system. But it's one kind of test that lets you
split the testing effort into less complex units, especially if your
system is in fact assembled from smaller units.

Unit testing frameworks provide mechanisms to isolate and setup the
program state after one test, so that when the next test begins,
you get a clean slate.
They also give you mechanisms to make it easier for you to reuse the
effort you put into setting the test environment for a test, because
in fact many tests will have the same setup. Those tests are then
made to be part of the same "TestCase".
A "TestCase" contains tests, and contains a setup method common
to all of them.



*What is an xUnit framework?*

It's a framework that allows you to write unit tests in a fashion that
goes well with TestDrivenDevelopment and TestFirstDesign.

It's also a kind of "meme" that got spread to most programming languages.
We owe the existance of this powerful meme to Kent Beck, and his SUnit
framework.
Arguably, the most popular incarnation nowadays is JUnit
(https://en.wikipedia.org/wiki/JUnit).

This "meme" consists of at least the following elements:

   * TestCases as classes (with setup() and teardown() methods).

   * Tests as methods of TestCases.

   * Convenience assert functions.

   * A green progress bar that turns to red when one of the Tests fails.

   * Pluggable console or GUI "test runners".

So, the user writes a class... that contains methods... which in turn contain
asserts.
The user then compiles the program or library and starts the "test runner",
which
then runs all the tests. Some runners display the list of available TestCases,
and
allow to pick which ones to run (or re-run):

    NUNIT: http://nunit.org/docs/2.5/img/gui-screenshot.jpg

    NUNIT CONSOLE: http://nunit.org/docs/2.6/img/console-mock.jpg

    JUNIT: http://www.eclipse.org/screenshots/images/JavaPerspective-WinXP.png
    (bottom part of the IDE screenshot)

    CPPUNIT: http://sourceforge.net/apps/mediawiki/cppunit/nfs/project/c/cp/cppunit/8/81/Mfctestrunner.png

    CPPUNIT CONSOLE:
http://sourceforge.net/apps/mediawiki/cppunit/index.php?title=File:Cursetr_RunningTests.png

Note the presence of the tipical green progress bar (which turns red when
one test fails, giving fast feedback to the user, and acting as a reinforcement
when green. It only keeps the green when *all* tests pass (no failing asserts).


*But how does the 'test runner' know which methods are tests to run?*

Each programming language has its own best way of marking a class as a TestCase,
and of marking a method in it as a Test to be run.

   With JUnit3, one had to inherit the class from a specific base class.
A test runner would have to use Reflection to get the list of all
classes that were TestCases to present them to the user. And then use
reflection to search for and list the methods whose names start with "test".

   With JUnit4, the user now has to only mark methods with the  Test attribute.
Through reflection, test runners can find all the classes which contain
methods marked with the  Test attribute, and then call those methods.
This still has some overhead, (hopefully not on the order of methods of the
program)
and we are talking about late-binding too.

   With C++, since there is absolutely no real reflection capability (like
getting all the names of the methods of a TestCase class). So one has to
manually
register the test method using macros. So, each time that you add a
new test method, you have to type its name at least three times. The result
is not beautiful: cppunit.sourceforge.net/doc/lastest/money_example.html
(but it's efficient though).


*How does DUnit do it?*

In DUnit classes are marked as a TestCase by declaring a "mixin TestMixin"
once in any part of their body. You don't need to type the name of a method
more than once, or the name of the class more than once. The mixin gets
it all from the context in which it was instantiated (thanks to "typeof(this)").
It creates a static constructor for the class, with:

    . a compile time generated immutable list of the names of the Test methods
      of the class whose names begin with "test" and can be called without
      arguments.
      (thanks to __traits(allMembers,), __traits(compiles,) and recursive
      template declarations).

    . a compile time generated function with a switch-case statement that takes
      the name of a Test and calls it.
      (thanks to __traits(allMembers) and __traits(compiles,) and recursive
      template declarations).

    . and a compile time generated function that can instantiate an object of
      that class. (thanks to string mixins).

When the program starts, the static constructors of each of the TestCases
registers those constants and function pointers with the dunit module,
for the test runners to see.
You can of course enclose your TestCases with something like
    version(DUnit) {
        ...
    },
so that you can exclude them from compilation for a release version.

The end result is that "test runners" are very easy to write, and it is also
extremely fast to get the list of TestCase classes, and in turn the list
of the Tests methods and setUp, tearDown, setUpClass and teardDownClass methods.
Calling a test function is also a switch statement away, and there is a
switch-case function per TestCase, so the list of switch cases is small.
The Test method is called directly from the switch-case,
there is no late binding at that point, because the switch is statically
generated as a string mixin.


This provides test runners with all the flexibility, since the test runner
knows the tests by name, and may call them by name. This means
that a test runner can let the user select which tests to run.

All of this also means that unit test writers only have to type the bare
minimum, unlike in C++, to define a test:

-------------------------
Minimum example:
-------------------------
import dunit;

class ATestCase {
   mixin TestMixin;

   void testtOne() {
       assert(true);
   }
}

-------------------------
Example:
-------------------------
import dunit;

class ATestCase {
   mixin TestMixin;

   void setUpClass() {
   }
   void tearDownClass() {
   }
   void setUp() {
   }
   void tearDown() {
   }

   void testtOne() {
       assert(true);
   }
   void test2() {
       assertEquals("str", "s"~"t"~"r);
   }
}


--jm
Feb 19 2012
parent hezz <ezzahir hhhh.com> writes:
alive dans ton petit village?
May 29 2012
prev sibling next sibling parent "Juan Manuel Cabo" <juanmanuel.cabo gmail.com> writes:
I forgot to mention. All of this works flawlessly with D2.057 and 
D2.058. But with previous versions, you might need to declare the:

        mixin TestMixin;

at the bottom of the class. Otherwise, the test* methods were not 
seen.


And excuse me for all the bad formatting in my post and all the 
excitement!

--jm
Feb 19 2012
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 2/19/12 9:30 AM, Juan Manuel Cabo wrote:
 People of the D world.. I give you DUnit (not to be confused with an old
 tango DUnit, this one is for >= D2.057, and doesn't really require
 phobos or tango (just you version the few writeln's of the runner, and
 maybe
 something else)).

 https://github.com/jmcabo/dunit

Interesting, congrats. A common question that will come up is comparing, contrasting, and integrating your work with the existing unittest language feature. You may want to address these issues directly in the documentation. Thanks, Andrei
Feb 19 2012
parent Jacob Carlborg <doob me.com> writes:
On 2012-02-19 19:18, Juan Manuel Cabo wrote:
 Interesting, congrats. A common question that will come up is
 comparing, contrasting, and integrating your work with the existing
 unittest language feature. You may want to address these issues
 directly in the documentation.

Thanks!! I'll put it in the doc (and also clean up my crude documentation formatting). I plan to keep improving dunit too.

You can can write the README file using markdown, github understands that format.
 * DUnit provides a style of unit testing popularized in the OOP crowd
 which begun with sUnit by Kent Beck (smalltalk), later jUnit by Kent Beck
 and Erich Gamma (java), and then also NUnit for .NET (there also exists
 too FlexUnit for Flex, FireUnit for Javascript, CppUnit for C++ etc., but
 those deviate a little from the originals).
 So DUnit brings D to the familiy of languages that support certain
 testing idioms familiar to many OOP developers. (tests fixtures (grouped by
 classes), with common initialization, green bars ;-), decoupled test
 runners,
 convenience assert functions, etc.
 (I'm thinking of writing a quick DWT GUI test runner too

Cool.
 # (OFFTOPIC: I made a patched DWT that works in linux 64bits (by fixing
 a few bugs and commenting out some impossible XPCOM code
 and I'll try to sync to Jacob Carlborg's github repo
 when I have more time; and fixed missing 'double vars=0' inits instead of
 NaN that produced slowdowns and prevented certain drawing functions
 from working in the Graphics Context)).
 --jm

Pull requests are welcome. -- /Jacob Carlborg
Feb 19 2012
prev sibling next sibling parent "Juan Manuel Cabo" <juanmanuel.cabo gmail.com> writes:
 Interesting, congrats. A common question that will come up is 
 comparing, contrasting, and integrating your work with the 
 existing unittest language feature. You may want to address 
 these issues directly in the documentation.

Thanks!! I'll put it in the doc (and also clean up my crude documentation formatting). I plan to keep improving dunit too. To answer quickly: * The convenience couple of assertEquals() that I defined, do work by throwing core.exception.AssertError. This means that they can be used inside the classic unittest{} blocks, if you import dunit. * The classic assert() statement can be used inside DUnit tests. * One could run DUnit tests when passing -unittest to dmd. Just define once somewhere in your project: unittest { import dunit; dunit.runTests(); } And all the classes in your project that are marked as DUnit tests with mixin TestMixin; will get run, no matter which module they are in. * DUnit also shows exceptions which are not asserts. Those are displayed as 'Errors' instead of 'Failures' (as the java style). * DUnit will not halt the execution of the program if a test fails. It will keep going with the next test. This is very useful when combined with: unittest { import dunit; dunit.runTests(); } On the other hand, D's classic unittests would halt the execution at the first failure. * D's classic unittest{} blocks are more straightforward and instantaneous to learn, and support a brief style of writing unit tests that DUnit is not meant for. * DUnit provides a style of unit testing popularized in the OOP crowd which begun with sUnit by Kent Beck (smalltalk), later jUnit by Kent Beck and Erich Gamma (java), and then also NUnit for .NET (there also exists too FlexUnit for Flex, FireUnit for Javascript, CppUnit for C++ etc., but those deviate a little from the originals). So DUnit brings D to the familiy of languages that support certain testing idioms familiar to many OOP developers. (tests fixtures (grouped by classes), with common initialization, green bars ;-), decoupled test runners, convenience assert functions, etc. (I'm thinking of writing a quick DWT GUI test runner too # (OFFTOPIC: I made a patched DWT that works in linux 64bits (by fixing a few bugs and commenting out some impossible XPCOM code and I'll try to sync to Jacob Carlborg's github repo when I have more time; and fixed missing 'double vars=0' inits instead of NaN that produced slowdowns and prevented certain drawing functions from working in the Graphics Context)). --jm On Sunday, 19 February 2012 at 16:36:53 UTC, Andrei Alexandrescu wrote:
 On 2/19/12 9:30 AM, Juan Manuel Cabo wrote:
 People of the D world.. I give you DUnit (not to be confused 
 with an old
 tango DUnit, this one is for >= D2.057, and doesn't really 
 require
 phobos or tango (just you version the few writeln's of the 
 runner, and
 maybe
 something else)).

 https://github.com/jmcabo/dunit

Interesting, congrats. A common question that will come up is comparing, contrasting, and integrating your work with the existing unittest language feature. You may want to address these issues directly in the documentation. Thanks, Andrei

Feb 19 2012
prev sibling next sibling parent "Marc P. Michel" <lanael free.fr> writes:
On Monday, 20 February 2012 at 01:49:04 UTC, Juan Manuel Cabo 
wrote:
 I thought I could do a better effort to describe why DUnit is 
 so extraordinary,
 for a native language, especially for those unfamiliar with 
 xUnit frameworks

This is great stuff, thanks ! Anyway, I'm not fond of your examples; so here is a silly one from me : http://lanael.free.fr/summertest.d.html
Mar 17 2012
prev sibling next sibling parent "Marc P. Michel" <lanael free.fr> writes:
Oh and also, changing "version(linux)" with "version(Posix)" for 
the color output management would be great. ( I'm on FreeBSD and 
was wondering why I had no colors as advertised :} ).
Mar 18 2012
prev sibling next sibling parent "Juan Manuel Cabo" <juanmanuel.cabo gmail.com> writes:
On Saturday, 17 March 2012 at 12:30:49 UTC, Marc P. Michel wrote:
 On Monday, 20 February 2012 at 01:49:04 UTC, Juan Manuel Cabo 
 wrote:
 I thought I could do a better effort to describe why DUnit is 
 so extraordinary,
 for a native language, especially for those unfamiliar with 
 xUnit frameworks

This is great stuff, thanks !

You're welcome! I'm glad that you tried it!!
 Anyway, I'm not fond of your examples; so here is a silly one 
 from me :

 http://lanael.free.fr/summertest.d.html

It's nice and clear indeed. If you put a BOOST licence header and your name in your 3 example files, I'll add it to github. Yeah, the example.d is a bit rough because I wanted to show all that you can do with dunit quickly in single file. --jm
Mar 21 2012
prev sibling next sibling parent "Juan Manuel Cabo" <juanmanuel.cabo gmail.com> writes:
On Sunday, 18 March 2012 at 11:05:59 UTC, Marc P. Michel wrote:
 Oh and also, changing "version(linux)" with "version(Posix)" 
 for the color output management would be great. ( I'm on 
 FreeBSD and was wondering why I had no colors as advertised :} 
 ).

Yeahp, will fix it. Sorry! Thanks for finding that! Still haven't had the time to get back to dunit, but I will eventually, and also make a proper documentation. I'm also going to make the whole family of assert functions, (assertNotNull, assertNotEquals, etc.) but I'm not sure where to put the optional 'message' argument (first or last). To be compatible with the java style, 'message' would go first. But that would have two issues: - It's different than D's assert where 'message' goes last. - "assertNotNull(someStr, "message");" would compile and you wouldn't have a clue that "message" was supposed to go as first argument. Btw, here is the whole list: http://www.junit.org/junit/javadoc/3.8.1/junit/framework/Assert.html Do you have any thoughts? --jm
Mar 21 2012
prev sibling next sibling parent "Rio" <rio orum.dlang.org> writes:
On Wednesday, 21 March 2012 at 17:29:59 UTC, Juan Manuel Cabo
wrote:
 Btw, here is the whole list:
     
 http://www.junit.org/junit/javadoc/3.8.1/junit/framework/Assert.html


 Do you have any thoughts?

Be careful: for JUnit 4 there is a separation of concerns. The assertions are now the responsibility of the Hamcrest library: http://code.google.com/p/hamcrest/ (Wouldn't it be nice to have a port to D?) On the other hand, D/JUnit "just" provides the frame for the test cases. Here are some ideas for this DUnit frame (from the previous DUnit): - provide means to let a test case pass iff an expected exception is thrown - use command-line args to filter test cases to be executed - add an XML test report for inspection by machines
Mar 21 2012
prev sibling next sibling parent "Juan Manuel Cabo" <juanmanuel.cabo gmail.com> writes:
On Wednesday, 21 March 2012 at 20:04:39 UTC, Rio wrote:
 On Wednesday, 21 March 2012 at 17:29:59 UTC, Juan Manuel Cabo
 wrote:
 Btw, here is the whole list:
    
 http://www.junit.org/junit/javadoc/3.8.1/junit/framework/Assert.html


 Do you have any thoughts?

Be careful: for JUnit 4 there is a separation of concerns. The assertions are now the responsibility of the Hamcrest library: http://code.google.com/p/hamcrest/ (Wouldn't it be nice to have a port to D?)

Not true. Regular asserts are still regular asserts in junit4. Hamcrest is supported for other kinds of asserts. The only care taken must be to consider an assert as something that throws core.exception.AssertError, which is already done. You can create your own kinds of asserts. Also, for mock objects, take a look at BlackHole and WhiteHole in std.typecons. That, together with anonymous classes pretty much is all you need for basic mock objects for testing.
 On the other hand, D/JUnit "just" provides the frame for the 
 test
 cases.

Exactly.
 Here are some ideas for this DUnit frame (from the previous
 DUnit):
 - provide means to let a test case pass iff an expected 
 exception is thrown

You already have it: std.exception.assertThrown().
 - use command-line args to filter test cases to be executed

Nice, I'll implement in the DUnitMain mixin.
 - add an XML test report for inspection by machines

Not big on the priority list, but yes, some kind of automation for Ant and IDEs would be cool. The reason I tried to stay compatible with java style tests output is so that some existing tools might already be able to parse it. For xml output, I would layout the output in some form that is already recognized by tools, and that would take me some time. And this DUnit is still too green (but 100% solid and usable in what it provides). I first want to do a graphical test runner. I also want to have the runner precompiled outside. So that I can stay in the test runner window, and just click 'retest' after recompiling. I got very used to this rhythm of work, and I think it'd be nice to have it in D. For that to work, I have to solve a few issues. Also, I don't want to make a graphical test runner that only works on windows or only works on unix. And I love DWT, so I first want a DWT that everyone can depend on. I already made DWT compile in linux 64bit which didn't work (though not as a library, that had some issues of its own, instead, I have to list aaalll the DWT files used in the dmd command line). So my priorities are (for when I have time!!): -Merge to latest DWT (I diverged last year when dmd 2.0.54 was newest) and make a pull request for DWT. -Add more assert* to DUnit, finalizing its API so to speak. Any other future DUnit change will be source compatible. (at least until D gets user defined attributes!). -Solve the 'test runner compiled outside' issues. -Make a graphical test runner, the nicest, slickest, coolest one of the *Unit bunch!! --jm
Mar 21 2012
prev sibling next sibling parent "Shripad K" <assortmentofsorts gmail.com> writes:
How do I test callbacks/delegates which are not triggered 
immediately? Especially when I need to do unit tests with an 
event loop?
A simple example from my codebase (SaaSy here is a custom HTTP 
client to an API endpoint):

class TestSaaSy {
     mixin TestMixin;

     // this works
     void test_encoded_auth() {
         auto ev = new EventLoop;
         auto saasy = new SaaSy(ev, "test", "test");
         assert(saasy.encoded_auth == "dGVzdDp0ZXN0dGVzdA==", 
"encoding issue");
         ev.close;
         ev.run;
     }

     // won't work. test gets finished even before the callback is 
fired!
     void test_get_subscription() {
         auto ev = new EventLoop;
         auto saasy = new SaaSy(ev, "test", "test");
         saasy.getSubscription("ref363466", (bool err, string 
response) {
             assert(err == true);
             ev.close;
         });
         ev.run;
     }
}

On Sunday, 19 February 2012 at 15:30:33 UTC, Juan Manuel Cabo 
wrote:
 People of the D world.. I give you DUnit (not to be confused 
 with an old
 tango DUnit, this one is for >= D2.057, and doesn't really 
 require phobos or tango (just you version the few writeln's of 
 the runner, and maybe
 something else)).

       https://github.com/jmcabo/dunit

 I've been developing it for the past few weeks, and since I saw 
 a post of another unit testing framework just a few minutes 
 ago, I thought I'd rush it to github.

 Soooo, here is how you define a test:


 import dunit;

 class Something {
     mixin TestMixin;

     void testOne() {
         assert(1 == 1, "this works");
     }

     void testTwo() {
         assertEquals(1, 2/2);
         assertEquals("a string", "a"~" string");
     }
 }

 .. and that's all there is to it. Put the mixin TestMixin, and 
 name your tests
 starting with 'test'. The results output shows all of them even 
 if some fail, and... guess what, it tells you the name of the 
 unit tests that failed!! isn't this awesome!! (all thanks to 
 mixins, recursive template declarations, __traits, and a little 
 bit of CTFE)... isn't D like, so incredibly awesome or what!?!?

 There is absolutely no overhead in registering the tests for 
 the test runner.. its all at compile time!

 Your tests are inherited through derived classes, and can be 
 private in the unit test class (they will still run).


 I made two test runners:

     * One that shows the results in java style (but WITH 
 COLORS!! (fineprint: colors only on unix console, windows 
 console is colorless for now)

     * Another one more verbose that shows the tree of tests as 
 it runs them.

 It is very easy to make your own.


 This is all BOOST licenced, so please tweak it away!


 FINEPRINT yes shouting fineprint ;-) haha:
 THIS IS NOT A unitest{} REPLACEMENT, JUST AN ITCH EVERY OOP 
 PEOPLE WANTED TO SCRATCH: named, easy, xUnit style unit tests.. 
 AND NOW YOU'VE GOT THEM.

Aug 29 2012
prev sibling next sibling parent "xenon325" <1 mail.net> writes:
Just for your information, the name "DUnit" is already used by 
Delphi.
Probably, you should name it "D2Unit" or "MarsUnit" ?
Aug 30 2012
prev sibling next sibling parent "linkrope" <linkrope github.com> writes:
Add some variable to the test case: bool finished;
Set the variable in the callback: finished = true;
Add something like

     assertWithTimeout({return finished;});

at the end of the test case, following ev.run;

Does it help?

On Wednesday, 29 August 2012 at 19:20:25 UTC, Shripad K wrote:
 How do I test callbacks/delegates which are not triggered 
 immediately? Especially when I need to do unit tests with an 
 event loop?
 A simple example from my codebase (SaaSy here is a custom HTTP 
 client to an API endpoint):

 class TestSaaSy {
     mixin TestMixin;

     // this works
     void test_encoded_auth() {
         auto ev = new EventLoop;
         auto saasy = new SaaSy(ev, "test", "test");
         assert(saasy.encoded_auth == "dGVzdDp0ZXN0dGVzdA==", 
 "encoding issue");
         ev.close;
         ev.run;
     }

     // won't work. test gets finished even before the callback 
 is fired!
     void test_get_subscription() {
         auto ev = new EventLoop;
         auto saasy = new SaaSy(ev, "test", "test");
         saasy.getSubscription("ref363466", (bool err, string 
 response) {
             assert(err == true);
             ev.close;
         });
         ev.run;
     }
 }

Aug 30 2012
prev sibling parent "Shripad K" <assortmentofsorts gmail.com> writes:
Sorry for the late reply. I thought I would be notified via mail 
of your reply but I don't think this forum sends alerts. Thanks 
for this suggestion. However its a bit different in the case of 
event loops (unlike threads, where a thread.start() would spawn a 
new thread and bring the control back to the calling block). The 
ev.run is blocking. So any code in the block that contains ev.run 
will not get executed if placed after the ev.run line.

It would be great if the tests themselves end manually via 
asserts themselves and the final report is displayed after 
collecting results from all asserts.
Aug 31 2012