Contest is a minimalist, cross platform, testing framework for .NET.
C# Other
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.


Contest is a minimalist, cross platform, unit testing framework for .NET. It comes bundled with a lightweight console test runner and in contrast with most popular testing frameworks, it's based on conventions, so it doesn't require a whole lotta of attributes to identify test cases, setups, and so on... Point in case, the code reads almost like plain english. (And of course, it runs on linux and mac as well!)

Down below you’ll find a couple of examples on how to write tests using contest. Just add a reference to Contest.Core.dll and you are pretty much ready to go.

As you will see in the examples below, contest supports a wide range of assertions and testing styles which you can mix and match to meet your preferences. From fluent assertions to BDD (and everything in between), contest will help you to find a style that you enjoy while writing tests.

*Note: While this is working code, is not production ready (yet). It'll be relased in the near future, tough. Stay tuned!

Fluent Assertions

	// This using statement enables fluent assertions.
	using static Contest.Core.Chatty;
	using _  = System.Action<Contest.Core.Runner>;

	// Some basic math
	_ add_two_numbers = assert => That(2 + 2).Is(4);

	// Login system
	_ when_an_admin_usr_logs_in = assert => That(usr.IsAdmin).IsTrue();

	_ regular_users_shouldnt_have_root_access = assert => That(regUsr.HasRootAccess).IsFalse();


For those who like the BDD approach better, you may wanna try contest's BDD API.

	using static Contest.Core.BDD;
	using _  = System.Action<Contest.Core.Runner>;

	// Some basic math
	_ add_two_numbers   = expect => (2 + 2).ToBe(4);
	_ mul_two_numbers   = expect => (2 * 3).NotToBe(5);

	// Login system
	_ when_an_admin_usr_logs_in = exect => usr.IsAdmin.ToBe(true);

	_ regular_users_shouldnt_have_root_access = expect => regularUsr.HasRootAccess.ToBe(false);

	// Alternative syntax. (It's handy to test exceptions and stuff like that).
	_ cant_access_members_on_null_pointers = assert => {
		object obj = null;

		// you can go this way
		Expect(() => obj.ToString()).ToThrow<NullReferenceException>();

		// or this way
		Expect(() => obj.ToString()).ErrMsg("Object reference not set to an instance of an object");

		// or this other way
		Expect(() => obj.ToString()).ErrMsgContains("reference not set to an instance");
	// You can also use:
	// * ToBeGreatThan
	// * ToBeGreatThanOrEqual
	// * ToBeLessThanOrEqual
	// * ToBeLessThan

	// Comming soon:
	// * NotToBeGreatThan
	// * NotToBeGreatThanOrEqual
	// * NotToBeLessThanOrEqual
	// * NotToBeLessThan

Plain old "lambda syntax"

This is the original contest's syntax and it works the same way always did.

	using _  = System.Action<Contest.Core.Runner>;

    /// Basic features.
    class Contest_101 {

		_ passing_test = assert => 
			assert.Equal(4, 2 + 2);

		_ failing_test = assert =>
			assert.Equal(5, 2 + 2);
		_ expected_exception_passing_test = test =>
			test.ShouldThrow<NullReferenceException>(() => {
				object target = null;
				var dummy = target.ToString();
				//================^ null reference ex.
		_ expected_exception_failing_test = test =>
			test.ShouldThrow<NullReferenceException>(() => {
				//It doesn't throws; So it fails.
    // Per fixture setup/teardown.
    class Contest_102 {
		// Fixture setup.
		_ before_each = test => {

		// Fixture teardown.
		_ after_each = test => {
		// Actual test cases.
		_ should_find_existing_users = assert => 

		_ should_return_null_when_cant_find_users = assert => 

		_ should_add_new_users = assert => {
			assert.Equal(4, User.Count());

	// Per test case setup/teardown.
	class Contest_103 {
		_ before_echo = test => 
			test.Bag["msg"] = "Hello World!";

		_ after_echo = test => 
			test.Bag["msg"] = null;

        //actual test.
		_ echo = test => 
			test.Equal("Hello World!", Utils.Echo(test.Bag["msg"]));

Wanna hack right away

Just go to and take contest for a spin.

Syntax Sugar

If you like the lambda approach but also like to write as less code as possible, you can go with contest's syntax sugar.

	using _  = System.Action<Contest.Core.Runner>;

	// By adding this using statement you have access
    // to the whole constest API thru helper methods.
	using static Contest.Core.SyntaxSugar;

    class TestSomeSugar {
		// Instead of writing this:
		_ passing_test = assert => 
			assert.Equal(4, 2 + 2);

		// You can write this:
		_ passing_test = assert => Equal(4, 2 + 2);

		//*(It is less code and also reads better without the second assert word).


Contest Core API

I guess this section is selfexplanatory ;)

	IsNull(value [, errMsg])
	IsNotNull(value [, errMsg])
	IsTrue(cond [, errMsg = null])
	IsFalse(cond [, errMsg = null])
	Equal(expected, actual [, errMsg])
	NotEqual(expected, actual [, errMsg])
	Assert(bool cond [, string errMsg]

	// Errors checking.
	ErrMsgContains(text, action);
	ErrMsg(msg, action);

	// Utility methods.
	// Increases the failing tests count and prints the err msg.

	// Increases the passing tests count.

How to add assembly level initialization code

Sometimes you need to execute a piece of code before running any test case. With contest you can do that by adding a special type to your project. Just add a new class called ContestInit, create a Setup method and put the initialization code in it.

using Contest.Core;

public class ContestInit {
	void Setup(Runner runner) {
		runner.Bag["album"] = "Rock or Bust!";

(*) To avoid false positives or corrupt state, contest will abort the execution if this method fails.

How to add assembly level cleanup code

Contest also allows you to run code when it finishes running tests. To do this you will need to add another special type called ContestClose. In this case you'll have to create a Shutdown method and put the cleanup code in there.

using Contest.Core;

public class ContestClose {
	void Shutdown(Runner runner) {
		// Some cleanup code...
  • Keep in mind that these special types are meant to used for global (assmebly level) configuration. If you need test level or class level configuration, use the before/after callbacks instead. (As shown in the samples above).

How to add class level initialization code

Use this technique when you want a piece of code to run once (and only once) before any test within the class. *(We 've been trying different approaches for this particular feature but in the end, plain old constructors ended up being the best choice).

	class FooTest {
		public FooTest () {
			// Your init code goes in here.

How to add class level cleanup code

Just modify your test class to implement the IDisposable interface and put your cleanup code inside the dispose method. Contest will execute this method before exiting the program.

	class BarTest : IDisposable {

		public void Dispose() {
			// Cleanup code in here.

How to install

Obviously, you can clone the repo, build from sources and get the binaries. But you can also get contest from nuget

How to run

The easiest way to run contest, it's by adding contest.exe to your path. Once you 've done that, you can go to whatever directory and just execute:

contest run test\_cases.dll

How to debug test cases

If you were using VS + ReSharper or TestDriven.NET or similar tools, chances are that when you find a failing test you wanna place a breakpoint and do some step by step debugging, right?

Well, while contest doesn't have an integrated "VS experience", you still have the chance to debug your tests using a switch that will freeze the execution and let you attach the VS debugguer. Just place a breakpoint as usual, run contest using the -dbg switch, attach the VS's debugger, and go back to the console and hit [Enter].

 contest run test\_cases.dll -dbg

I know, this is far from ideal... but keep in mind that contest it's meant to be used from the console. (And I wanna keep it as lightweight as possible). If you are using this library is probably because you are doing TDD on a plain text editor, which in such case, you don't have a debugger anyways, so...

Cherry picking

You can use wildcards to ask Contest to filter your fixtures and only run matching tests.
contest run test.dll *test_name_contains*
contest run test.dll test_name_starts_with*
contest run test.dll *test_name_ends_with

How to test your code under different cultures.

Often times you have to make sure that your code works under different regional settings. Some testing frameworks allow you to do that by adding data annotations to your test cases, something like this:

public void FooTest() {
    // Your culture sensitve test case.

Although it works, it's really tedious. With contest you can achieve the same thing without touching your code.

# Want to test under es-AR.
contest run test.dll * -ci es_AR

# Also, en-US. No problem!
contest run test.dll * -ci en_US

The -ci flag allows you to override the culture that contests will use to run your test cases. So if you set that flag, the whole thing will run under that specific culture.

Note: If you want to run just some test cases under a specific culture and let the rest as is, you can use wildcards to so.

# Just test the Foo module under es-AR
contest run test.dll *Foo* -ci es_AR

How to rerun failing tests

Most tests runners comes with a handy feature that allows you to filter and run only test cases that had failed in the previous run. (I used this feature a lot with ReSharper's test runner). You can do this with contest too, just add the -f flag and you are all set.

 contest run test\_cases.dll -f
  • You can also see failing tests without running them using the -lf flag.
 contest run test\_cases.dll -lf

How to look for slow tests

Weather if your are fixing performance issues or just wanna speed up your tests, contest can tell you where to start. Just run:

 contest run test/_cases.dll -yslow

The command above will print a list of test cases sorted by execution time. (Slowest tests first). You can combine this command with less or any tool like that and get the top 10/20 cases that worth to look at.

You can also list fastest tests firts. (OK, I don't see a point either, but it was just two lines away ;))

 contest run test/_cases.dll -yfast

How to ignore tests using .test_ignore file.


How to report issues

The best way to report an issue is by providing a failing test case. Wich is dead simple if you use

Whether if you have problems using this library, found a bug o wanna a new feature, feel free to contact me. I'll be back at you as soon as a I can.