Last active
December 21, 2017 17:31
-
-
Save ExpandingMan/1db7b6038135eb8fffc9c0810c2e298b to your computer and use it in GitHub Desktop.
rough, primitive proof-of-concept for automated random unit testing in Julia
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Base.Test | |
using MacroTools | |
""" | |
argnametype(arg::Expr) | |
Given an argument of the form `x::DType` extracts the argument name (`x`) and | |
data type (`DType`) as a tuple. | |
""" | |
function argnametype(arg::Expr) | |
if @capture(arg, x_::T_) | |
return x, T | |
end | |
throw(ArgumentError("Malformed argument $arg")) | |
end | |
""" | |
randex(dtype::Symbol) | |
Generates an expression creating a random instance of the type `dtype`. | |
**TODO** Would have to implement `rand` for every possible argument type. | |
""" | |
randex(dtype::Union{Symbol, <:Type}) = :(rand($dtype)) | |
""" | |
gentest(fname::Symbol, args::Vector) | |
Generate an expression for testing the function of name `fname` on argument expressions. | |
""" | |
function gentest(fname::Symbol, types::Vector{Symbol}) | |
ex = :(@test ($fname($(randex.(types)...)); true)) | |
Expr(:quote, ex) | |
end | |
gentest(fname::Symbol, args::Vector) = gentest(fname, Symbol[x[2] for x ∈ argnametype.(args)]) | |
""" | |
@gentest function f(x::DT1, y::DT2, z::DT3) | |
# body | |
end tests | |
Declares the function provided and appends an expression with a random unit tests to the container | |
`tests`. | |
""" | |
macro gentest(func, tests) | |
@capture(func, function f_(args__) body_ end) | |
esc(quote | |
$func | |
push!($tests, $(gentest(f, args))) | |
end) | |
end | |
""" | |
runtests(expr::Expr, N::Integer) | |
Runs test given in the expression `expr` `N` times. This is for cases in which | |
`expr` contains calls to an RNG so that the tests are different each time. | |
""" | |
function runtests(expr::Expr, N::Integer) | |
for i ∈ 1:N | |
eval(expr) | |
end | |
end | |
#=============================================================================================== | |
**EXAMPLE** | |
Here we have an example of our very simple proof-of-concept for automated random unit | |
testing. We declare a function `f` and test that it executes without errors 5 times. | |
Distinct random inputs are generated on each test run. | |
===============================================================================================# | |
tests = Vector{Expr}() | |
@gentest function f(x::Float64, y::Int64) | |
x + y | |
end tests | |
@testset begin | |
runtests.(tests, 5) | |
end | |
#===============================================================================================# |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment