Testing D database calls code for regression

H. S. Teoh hsteoh at quickfur.ath.cx
Fri Mar 16 21:15:33 UTC 2018


On Fri, Mar 16, 2018 at 08:17:49PM +0000, aberba via Digitalmars-d-learn wrote:
> How will you test D code which makes calls to database to detect bugs
> and regression. Unlike where you can inject data like assert (2+1 ==
> 3), database interfacing code will be crazy... Or there's some mocking
> available for such cases. Especially when more features are developed
> on top.

The usual way I do this is to decouple the code from the real database
backend by templatizing the database driver.  Then in my unittest I can
instantiate the template with a mock database driver that only
implements the bare minimum to run the test.

For example, instead of:

	import database : Database;
	auto myQueryFunc(Args...)(Database db, Args args) {
		return db.query(...);
	}

Do this:

	import database : Database;
	auto myQueryFunc(Db = database.Database, Args...)(Db db, Args args) {
		return db.query(...);
	}

Then regular calls to myQueryFunc will call the real database backend,
as usual. But in the unittest:

	unittest {
		struct FakeDb {
			auto query(...) {
				// mock implementation here
			}
		}
		FakeDb db;

		// test away
		assert(myQueryFunc(db, ...) == ... ); // uses FakeDb
	}

This applies not only to database backends, but just about anything you
need to insert mockups for.  For example, for testing complicated file
I/O, I've found it useful to do this:

	auto myFunc(File = std.stdio.File, Args...)(Args args) {
		auto f = File(...);
		// do stuff with f
	}

	unittest
	{
		struct FakeFile {
			this(...) { ... }
			// mockup here
		}
		assert(myFunc!FakeFile(...) == ... );
	}

Using this method, you can even create tests for error-handling, like a
simulated filesystem that returns random (simulated) I/O errors, or
exhibits various disk-full conditions (without actually filling up your
real disk!), etc..  I've created tests for code that searches
directories for files, by substituting a fake filesystem that contains
pre-determined sets of files with content that only exist inside the
unittest.  This way, I can run these tests without actually modifying my
real filesystem in any way.

If you push this idea far enough, you might be able to write unittests
for simulated syscalls, too. :-D  (Maybe that's something we could do in
druntime... :-P)


T

-- 
May you live all the days of your life. -- Jonathan Swift


More information about the Digitalmars-d-learn mailing list