sut

所属分类:编程语言基础
开发工具:D
文件大小:0KB
下载次数:0
上传日期:2023-10-01 10:36:54
上 传 者sh-1993
说明:  一种用于选择性单元测试执行的D编程语言单元测试库,允许每个模块和每个单元测试块的执行。,
(A D programming language unit testing library for selective unit test execution allowing per module and per unit test block execution.,)

文件列表:
CHANGELOG.md (66, 2023-11-07)
LICENSE (1076, 2023-11-07)
archive.sh (650, 2023-11-07)
src/ (0, 2023-11-07)
src/sut/ (0, 2023-11-07)
src/sut/list/ (0, 2023-11-07)
src/sut/list/config.d (3061, 2023-11-07)
src/sut/list/container.d (6032, 2023-11-07)
src/sut/list/package.d (161, 2023-11-07)
src/sut/log.d (5005, 2023-11-07)
src/sut/mixins.d (3327, 2023-11-07)
src/sut/package.d (3551, 2023-11-07)
src/sut/runner/ (0, 2023-11-07)
src/sut/runner/custom.d (4028, 2023-11-07)
src/sut/runner/log.d (3019, 2023-11-07)
src/sut/runner/package.d (102, 2023-11-07)
src/sut/runner/runtime.d (303, 2023-11-07)
src/sut/stats/ (0, 2023-11-07)
src/sut/stats/exec_stat_counter.d (327, 2023-11-07)
src/sut/stats/module_stat.d (1879, 2023-11-07)
src/sut/stats/package.d (151, 2023-11-07)
src/sut/stats/stat.d (4378, 2023-11-07)
src/sut/stats/unittest_stat.d (1017, 2023-11-07)
src/sut/util.d (12883, 2023-11-07)
src/sut/wrapper.d (560, 2023-11-07)
src/test/ (0, 2023-11-07)
src/test/compile.sh (1847, 2023-11-07)
src/test/failing/ (0, 2023-11-07)
src/test/failing/excluded.d (334, 2023-11-07)
src/test/failing/mul.d (293, 2023-11-07)
src/test/failing/no_prologue.d (203, 2023-11-07)
src/test/failing/no_unittest.d (70, 2023-11-07)
src/test/failing/sut_wrapper.d (1058, 2023-11-07)
src/test/failing/test.d (628, 2023-11-07)
src/test/failing/unittest.conf (0, 2023-11-07)
src/test/no_wrapper/ (0, 2023-11-07)
src/test/no_wrapper/excluded.d (423, 2023-11-07)
src/test/no_wrapper/mul.d (326, 2023-11-07)
... ...

# Selective Unit Testing Unit testing library for selective unit test execution of D programs. It allows per module and per unit test block execution. ## Rationale The default unit test execution in D is all or nothing. That means all unit tests are executed every time. It is designed to ensure that all tests pass. What it does not address is the isolated testing of individual unit tests and modules. It is common that modifications, enhancements, refactorings, or reimplementations of a portion of a code base require the testing of only the concerned portion. At this point, the programmer is not yet concerned about integration. That comes after when the portion of the code has been tested to execute as expected. This is the missing part--a unit testing capability supporting the bottom-up approach. I believe that allowing execution of specific tests complements the all or nothing approach by providing a middle ground. It will aid the programmer to focus on the detail at hand. The programmer can try and test the concerned parts as often as necessary, without being untimely bothered by broken tests from other parts of the code base. Also, being able to test a unit in isolation saves clock cycles and, therefore, time. The faster turn around may become an encouragement to do more experiments, craft better tests, and be more productive. This library is an attempt to provide more unit testing flexibility and capability that is absent from the default unit test execution. ## Features The library provides the ability to run specific tests during development, maintenance, and enhancement efforts. It also allows the programmer to opt-out and revert to the default unit test execution if necessary. * __Unit Test Block Execution__ The programmer can choose to execute only a specific unit test block or a group of them that is of immediate concern. This helps the programmer to focus on the 'unit' without being bothered by other unit tests that may, at this point, fail. * __Module Unit Test Execution__ The programmer can also choose to execute all unit tests in a single module, also without being flooded with failed tests from other modules. * __Module Exclusion__ In contrast with the _Module Unit Test Execution_, the library also allows modules to be excluded from unit test execution. This feature is a consequence of determining which modules do not have unit tests. Packages that simply declare public imports are candidates for this. * __Detailed Reporting__ The library provides a detailed report of the unit test execution. * Reports the line number and _name_ of executed unit test blocks; * Summary of successful and failed unit test blocks per module; * Summary of all successful and failed unit test blocks; * List of modules with unit tests; * List of modules with unit tests but without `sut` prologue code; * List of modules without unit tests; * List of excluded modules from unit testing. ## Compiler Compatibility The following compilers have been tested under GNU/Linux only. I do not currently have a Microsoft Windows machine to test it. The oldest compiler used to execute the tests is version 2.090.0. It is not known what earlier versions can successfully compile and use the library. Latest versions of compilers to successfully compile and use the library are: * [DMD 2.104.2](https://dlang.org/download.html#dmd) * [LDC 1.33.0](https://github.com/ldc-developers/ldc/releases/tag/v1.33.0) ## Limitations * Cannot be used with `-betterC`. The library cannot be used if D source is compiled without `ModuleInfo`. That includes source codes being compiled with the `-betterC` flag since the flag disables the use of `ModuleInfo`. * Cannot be used with `@nogc`. * Cannot be used with `nothrow`. * Cannot be used with `pure`. ## Usage There are two ways to use the `sut` module: _basic_ and _selective unit testing_. __Basic Usage__ * incorporate the module into your project; * use a _Wrapper Module_; * statically import the _Wrapper Module_; * add _user-defined attributes_ before unit test blocks; * add unit test block prologue code at the top of unit test blocks; * pass the unit testing flag (--unittest) and the version identifier `sut` to the compiler. Unit tests without _user-defined attributes_ or unit test block prologue code will still execute but they will not be reported in the console output since the library uses the prologue code to collect information for reporting. __Selective Unit Testing__ * to select unit test blocks to execute, create/edit a _unit test configuration file_ and add unit test block entries; * to select modules to execute, create/edit a _unit test configuration file_ and add module entries; * pass the configuration file as command-line argument to the test program. ### Incorporating `sut` Module To use the module, the compiler must be able to _see_ its source code. This could be done using the `-I` compiler option for `dmd` or `ldc` and passing the path to the `sut` source code. The following shows an example of a project directory. It shows where the `sut` module may be placed. ~~~ ... `-- project |-- ... |-- build | `-- sut.conf // selective unit testing configuraiton file |-- extern | |-- sut // this module | `-- ... // other external dependencies `-- src // <<<<< we are here |-- main.d |-- module_a.d |-- module_b.d |-- sut_wrapper.d // sut wrapper module `-- ... ~~~ To compile the example project above, the following command may be used. ~~~ dmd \ -I=../../ \ # Look for imports in project/ -i \ -main \ -debug \ -unittest \ -version=sut \ # Version identifier for using this module -run \ test.d ~~~ ### SUT Wrapper Module The _wrapper module_ conditionally enables or disables the use of the library. The library is enabled by the use of the version identifier `sut`. See the _Version Identifier_ section below. It is possible to use the library without using a _wrapper module_. But using a _wrapper module_ makes it seemless to revert to the default unit test execution. ~~~d module sut_wrapper; version (sut) { static if (__traits(compiles, { import sut; })) { /** * Conditionally compile-in the `sut` module if it is visible in * the client code. Otherwise, it does nothing. */ pragma (msg, "Using selective unit testing module."); public import sut; /** * Unit test block prologue code mixed-in from unit test blocks. */ enum prologue=`mixin (sut_wrapper.unitTestBlockPrologue);`; enum exclude=`mixin (sut_wrapper.excludeModule);`; } else { pragma (msg, "Version identifier 'sut' defined but 'sut' module not found."); enum prologue=""; enum exclude=""; } } else { pragma (msg, "Using default unit test runner."); enum prologue=""; enum exclude=""; } ~~~ When using a wrapper module, calls to `unitTestBlockPrologue` and `excludeModule` are qualified with the _wrapper module_ name. This is because the client code imports the _wrapper module_ statically. See the following _Functions_ section. ~~~d module sut_wrapper; ... enum prologue=`mixin (sut_wrapper.unitTestBlockPrologue);`; enum exclude=`mixin (sut_wrapper.excludeModule);`; ~~~ It is possible not to statically import the _wrapper module_ but doing so may lead to possible name conflicts. It is therefore advised to follow the safer path and use `static import`. ### Functions The `sut` module provides the following functions to be used in a [`mixin`](https://dlang.org/spec/statement.html#mixin-statement) statement: * unitTestBlockPrologue * excludeModule The client code statically imports the _wrapper module_ as in the following: ~~~d version (unittest) { static import sut_wrapper; } ~~~ #### unitTestBlockPrologue The code controls whether to continue execution or return early from the block along and collects information about the unit test block. It is therefore necessary that it be in the first line inside the unit test block. The code looks for a [`user-defined attribute`](https://dlang.org/spec/attribute.html#uda) (UDA) for the unit test block and uses the first UDA string as the _unit test block name_. If it cannot find one, it uses the compiler-generated unit test block identifier. It is advised to use a UDA string to allow better identification of unit test blocks when using _selective unit test block_ execution. See the _Unit Test Configuration File_ section below on how to use this feature. ~~~d @("some name") unittest { mixin (sut_wrapper.prologue); ... } ~~~ #### excludeModule Adds the module name to an exclusion list. The unit test runner skips execution of the module unit tests if it finds the module name in the exclusion list. It is intended to be used at the top of the module possibly before or after import declarations. ~~~d version (unittest) { static import sut_wrapper; mixin (sut_wrapper.exclude); } ~~~ ### Version Identifier To use the library, the version identifier `sut` must be passed to the compiler. It is used by the `sut` module for conditional compilation and static checks. ~~~ $ dmd -version=sut $ ldc --d-version=sut $ ldmd2 -version=sut ~~~ ### Unit Test Configuration File The _unit test configuration file_ contains all unit test block and module names to be executed. They are then placed in an execution list. When the unit test runner determines that a module or a unit test block is found in the execution list, then they are executed. Otherwise, they are skipped. The _unit test configuration file_ must follows these formatting rules: * one item per line * unit test block names are prefixed with `utb:` * unit test block names can contain space * module names are prefixed with `utm:` * module names cannot contain spaces * empty lines and duplicates are ignored ~~~ utb: utb:... utm: utm:... ~~~ One or more _unit test configuration files_ can be passed to the test program via command-line argument using `-c` or `config` options: ~~~ -c -c --config= --config ~~~ #### Unit Test Block Names Unit test block names are checked in the execution list and executed when it is found. An example using the following _unit test block names_. ~~~d @("func one") ... @("func two") ... @("func three") ~~~ If the _unit test configuration file_ contains `utb:func t`, then the unit test blocks for `@("func two")` and `@("func three")` are executed. The unit test block for `@("func one")` will be 'skipped'. #### Module Names The same with the _Unit Test Block Names_, modules are executed conditionally. The all unit tests of a module is executed when the module name is present in the execution list. ## Basic Usage Example Let us begin with the _with_wrapper_ test program to demonstrate the basic use of the library without unit test filtering and show the console output. This test program has four D source files: * `test.d` - main module with a couple of unit tests. * `mul.d` - a module with a unit test to show per module and summary reporting output for such modules. * `excluded.d` - a module with a unit test to show how to exclude a module from unit test execution. * `no_unittest.d` - a module without a unit test to show summary reporting output for such modules. * `no_prologue.d` - a module with a unit test but does not use the prologue code. * `sut.conf` - unit test configuration file for this test program is empty which means there will be no filtering of unit tests. The following are the contents of each file starting with the main module. * __test.d__ ~~~d module test.with_wrapper.test; import test.with_wrapper.mul; import test.with_wrapper.no_prologue; import test.with_wrapper.no_unittest; import test.with_wrapper.excluded; version (unittest) { static import test.with_wrapper.sut_wrapper; // import } int add (const int arg, const int n) { return arg + n; } @("add") unittest { mixin (test.with_wrapper.sut_wrapper.prologue); // prologue code assert (add(10, 1) == 11); } int sub (const int arg, const int n) { return arg - n; } @("sub") unittest { mixin (test.with_wrapper.sut_wrapper.prologue); // prologue code assert (sub(10, 1) == 9); } ~~~ * __mul.d__ ~~~d module test.with_wrapper.mul; version (unittest) { static import test.with_wrapper.sut_wrapper; // import } size_t mul (const int arg, const int n) { return arg * n; } @("mul") unittest { mixin (test.with_wrapper.sut_wrapper.prologue); // prologue code assert (mul(10, 2) == 20); } ~~~ * __excluded.d__ ~~~d module test.with_wrapper.excluded; version (unittest) { static import test.with_wrapper.sut_wrapper; // import mixin (test.with_wrapper.sut_wrapper.exclude); // exclude module } int div (const int arg, const int n) { return arg / n; } @("div") unittest { mixin (test.with_wrapper.sut_wrapper.prologue); // prologue code assert (div(10, 1) == 10); // never executed } ~~~ * __no_unittest.d__ ~~~d /** * Module without unit test. */ module test.with_wrapper.no_unittest; ~~~ * __no_prologue.d__ ~~~d module test.with_wrapper.no_prologue; size_t square (const uint arg) { return arg * arg; } unittest { assert (square(10) == 100); } ~~~ Compile the source files using the following command: ~~~ $ dmd \ -I=./../../ \ -i \ -main \ -debug \ -unittest \ -version=sut \ -run \ test.d \ --config=unittest.conf ~~~ Note that using the `ldc2` compiler, you may replace `dmd` with `ldmd2` which is a wrapper that accepts dmd-style argument formats. ~~~ $ dmd \ > -I=../../ \ > -i \ > -main \ > -debug \ > -unittest \ > -version=sut \ > -run \ > test.d --config=unittest.conf Using selective unit testing module. [unittest] Start 2021-Apr-23 18:00:07.226723 [unittest] Digital Mars D version 2.96 [unittest] D specification version 2 [unittest] Mode: All [unittest] Module: test.with_wrapper.test 15 add [unittest] test.with_wrapper.test 24 sub [unittest] test.with_wrapper.test - 2 passed, 0 failed, 2 found - 0.000s [unittest] Module: test.with_wrapper.mul 11 mul [unittest] test.with_wrapper.mul - 1 passed, 0 failed, 1 found - 0.000s [unittest] ======================================== [unittest] Summary: 3 passed, 0 failed, 3 found [unittest] 3 module(s) with unit test [unittest] 1 module(s) without unit test [unittest] 1 module(s) excluded [unittest] List: Module(s) with unit test (3) [unittest] Module(s) without prologue code have asterisk (*) [unittest] test.with_wrapper.mul [unittest] test.with_wrapper.no_prologue * [unittest] test.with_wrapper.test [unittest] List: Module(s) without unit test (1) [unittest] test.with_wrapper.no_unittest [unittest] List: Module(s) excluded (1) [unittest] test.with_wrapper.excluded [unittest] End 2021-Apr-23 18:00:07.2269942 ~~~ ## Selective Unit Test Block Execution Example This example will be using the same _with_wrapper_ test program above. Choose one of the unit test blocks names you wanted to execute. Edit the _unit test configuration file_ and add an entry. * `utb:add` * `utb:sub` * `utb:mul` The _unit test configuration file_ should look something like: ~~~ utb:add ~~~ Compile the source files using the following command: ~~~ $ dmd \ -I=./../../ \ -i \ -main \ -debug \ -unittest \ -version=sut \ -run \ test.d \ --config=unittest.conf ~~~ Choosing `utb:add` shows the following output: ~~~ Using selective unit testing module. [unittest] Start 2021-Apr-23 18:02:56.9533576 [unittest] Digital Mars D version 2.96 [unittest] D specification version 2 [unittest] Mode: Selection [unittest] block: add [unittest] Module: test.with_wrapper.test 15 add [unittest] test.with_wrapper.test - 1 passed, 0 failed, 2 found - 0.000s [unittest] ======================================== [unittest] Summary: 1 passed, 0 failed, 3 found [unittest] 3 module(s) with unit test [unittest] 1 module(s) without unit test [unittest] 1 module(s) excluded [unittest] List: Module(s) with unit test (3) [unittest] Module(s) without prologue code have asterisk (*) [unittest] test.with_wrapper.mul [unittest] test.with_wrapper.no_prologue * [unittest] test.with_wrapper.test [unittest] List: Module(s) without unit test (1) [unittest] test.with_wrapper.no_unittest [unittest] List: Module(s) excluded (1) [unittest] test.with_wrapper.excluded [unittest] End 2021-Apr-23 18:02:56.9535918 ~~~ ## Selective Module Execution Example This example will be using the same _with_wrapper_ test program above. Choose one of the modules you wanted to execute. Edit the _unit test configuration file_ and add an entry. * `utm:test.with_wrapper.mul` * `utm:test.with_wrapper.test` The _unit test configuration file_ should look something like: ~~~ utm:test.with_wrapper.mul ~~~ Compile the source files using the following command: ~~~ $ dmd \ -I=./../../ \ -i \ -main \ -debug \ -unittest \ -version=sut \ -run \ test.d \ --config=unittest.conf ~~~ Choosing `utm:test.with_wrapper.mul` shows the following output: ~~~ Using selective unit testing module. [unittest] Start 2021-Apr-23 18:06:47.0770861 [unittest] Digital Mars D version 2.96 [unittest] D specification version 2 [unittest] Mode: Selection [unittest] module: test.with_wrapper.mul [unitte ... ...

近期下载者

相关文件


收藏者