This project is about a c#/.NET monkey-testing library I wrote that lets you test your code by including an attribute on your tests. Supports MSTest, NUnit and XUnit.
There’s a lot more detail and use-cases to be found on the project readme.
Monkey Testing and Random Testing are not new concepts. They are useful for testing your code beyond your cognitive blindspots and assumptions for how it is meant to be used/executed. This library allows you to test your functions with lots of random, ideally troublesome inputs. It tries to approximate easy-to-overlook values of primitive and complex types, that are arguments to the functions you want to test.
A while back, I was writing a c# library that would take in all sorts of value and reference types, and do some generic, valuable logic on them. And I realized that I wanted an easy way to test my library, with lots of different kinds of inputs. Like edge-case values for the arguments so I could test if my code was making assumptions. I had trouble finding an adequate “Monkey Testing” library, and so decided to write it myself (a library for a library - I do it a lot apparently).
I did a nuget search for “monkey testing” that would let me find similar packges, but I couldn’t find any that seemed to fit my needs.
Curious George uses reflection to figure out the types of arguments for the function. The four basic variations of values for a given type are the following:
It uses AutoFixture for creating random instances of user-defined classes. Here’s a table that sheds more light on the types of values generated for different types:
Types | Null | Default | Min | Max |
---|---|---|---|---|
byte | 0 | default(byte) | byte.MinValue | byte.MaxValue |
sbyte | 0 | default(sbyte) | sbyte.MinValue | sbyte.MaxValue |
int | 0 | default(int) | int.MinValue | int.MaxValue |
uint | 0 | default(uint) | uint.MinValue | uint.MaxValue |
short | 0 | default(short) | short.MinValue | short.MaxValue |
ushort | 0 | default(ushort) | ushort.MinValue | ushort.MaxValue |
long | 0 | default(long) | long.MinValue | long.MaxValue |
ulong | 0 | default(ulong) | ulong.MinValue | ulong.MaxValue |
float | 0.0f | default(float) | float.MinValue | float.MaxValue |
double | 0.0d | default(double) | double.MinValue | double.MaxValue |
char | '\0' | default(char) | char.MinValue | char.MaxValue |
bool | false | default(bool) | false | false |
string | null | default(string) | string.Empty | GetStringMax() |
decimal | 0.0M | default(decimal) | decimal.MinValue | decimal.MaxValue |
DateTime | DateTime.MinValue | default(DateTime) | DateTime.MinValue | DateTime.MaxValue |
In addition to that, where it finds lists/enumerables, it tries to make null, and empty versions of them to trigger any hidden null reference exceptions, or list length assumptions.
Curious George also tries to generate all possible combinations of inputs so you can test things in more detail. It will try to generate distinct
combinations of all your inputs.
For example, for the input argument type int
,
0
,default(int)
,int.MinValue
int.MaxValue
.Now for a function like FunctionToTest1(int a, int b, int c)
which takes in three ints, each of which can have one of 4 values (Null, Default, Min, Max) - all possible combinations of values is a total of 64 combinations (4 x 4 x 4 = 64).
Since int is a value type, the Null and Default values for it are both 0
.
CuriousGeorge will make sure that the result set returned is distinct, and that any given result set is never repeated - which brings the total number of combinations down to 27 (3 x 3 x 3 = 27).
allPossibleCombinations
is the last argument for the monkey test dataset creation.