linkrope / dunit

xUnit Testing Framework for D
Boost Software License 1.0
37 stars 9 forks source link

more usage info for newbies? #21

Open biocyberman opened 6 years ago

biocyberman commented 6 years ago

I ran the example.d, the output style of tests are something I would like to use for my code. However, reading example.d content, it is not clear to me what is the real code and what is the test code. And more practically, how do I migrate from the code using D built-in unittest to dunit.

For example, consider myDbuiltinTest.d:

import std.string: toLower;

string strToLower(string s){
  string ret;
  foreach(c; s) ret ~= toLower(c);
  return ret;
}

unittest{
  writeln("Test strToLower);
  assert("lower" == strToLower("LoWer"));
}
unittest{
  writeln("Test strToLower with unicode);
  assert(" lower2 ü" == strToLower(" LoWer2 Å"));
}

My questions:

  1. How do I make use of dunit in this case?
  2. And in case I want to run a particular test because hundreds of other tests have just been run, how do I do that?
  3. Finally when I want to run test for the whole project with multiple files, do I have to walk through all .d files and execute them individually?
linkrope commented 6 years ago
  1. Turn the unittest functions into member functions of a test class. For more helpful information about failures use assertEquals instead of assert:
    
    #!/usr/bin/env dub
    /+ dub.sdl:
    name "example"
    dependency "d-unit" version=">=0.8.0"
    +/

import dunit; import std.string: toLower;

string strToLower(string s){ string ret; foreach(c; s) ret ~= toLower(c); return ret; }

class StringTest { mixin UnitTest;

@Test
void testStrToLower()
{
    assertEquals("lower", strToLower("LoWer"));
}

@Test
void testStrToLowerWithUnicode()
{
    assertEquals(" lower2 ü", strToLower(" LoWer2 Å"));
}

}

mixin Main;


2. Just run the test `main` with option `-h` to discover your options:

./example -h


`--filter testStrToLower` selects both test functions, because both function names contain "testStrToLower". Use `std.regex` symbols to be more selective. `--filter  testStrToLower$` selects only the first test case.

3. In a large project extract the `mixin Main;` that generates the test `main` function in a single file. Compile or link all modules together. Then, the `mixin UnitTest;` registers each test class for the test execution.

By the way: it may be a good idea to separate the application (your `strToLower`) in a `src` directory from the test code (the class `StringTest`) in a `test` or `unittest` directory.

However, consider reading https://dlang.org/blog/2017/10/20/unit-testing-in-action/ for alternatives to _dunit_. 
biocyberman commented 6 years ago

Ah yes, those are very good pointers. The simple ./example.d -h trick is really helpful. I overlooked that.

By the way: it may be a good idea to separate the application (your strToLower) in a src directory from the test code (the class StringTest) in a test or unittest directory.

I see there are two big disadvantages when merging code and test code in one file:

  1. For libraries, downstream users may ends up running tons of unnecessary tests embedded in the library source.
  2. For large and complex modules, test code may be overwhelming to manage in the same file with code.

Anyway for small programs, or when exploring something not very well-known, it is very convenient to put code and test code in one file. Mentioning this, I miss IDE support for creating tests in Python and Java. It will be very nice if with shortcut keys we can create test cases for current function or class' method in a separate test file. And jump back and forth between code and test code :)

andre2007 commented 6 years ago

The DLang plugin for IntelliJ has support for DUnit, although it is quite limited at the moment. (You can only specify 1 test module for a test run configuration).