Programming Testing: Seams: Difference between revisions
Line 80: | Line 80: | ||
import "os" | import "os" | ||
var OsCreate = os.Create | var OsCreate = os.Create // exported function, we can override | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Revision as of 14:26, 23 July 2022
Seams are places where you can alter the behaviour of a program when it is under test.
The available seams depend on the programming language in use.
When designing a program for testing, you should provide seams to allow it to be tested.
PreProcessor Seams
TODO:
untested
In C/C++ and other languages with macros,
you can use an#ifdef
to inject or replace test methods.In the real file, we include
testmacros.h
,
which in our tests will define functions locally.// main.c #include <stdio.h> #include "libusers.h" #include "testmacros.h" // <-- when testing, define 'create_db_user' locally int main(int argc, char *argv[]) { int id = 100; create_db_user("foo@example.com", "foo"); // <-- this will use our macro defined func }In our macro, we define a function that fakes creating a user in the database.
// testmacros.h #ifdef TESTING struct User { int id; char *email; char *name; } User users[5] = {}; #define create_db_user(email, name) \ { \ struct User user; \ user.id = 123; \ user.email = email; \ user.name = name; \ users[0] = user; \ } #endif
Linker/Import Seams
You can alter the path code is sourced from to substitute in entirely new files.
CLASSPATH=test/foo:${CLASSPATH} # java GOPATH=test/foo:${GOPATH} # go PYTHONPATH=test/foo:${PYTHONPATH} # python
Package/Module Seams
If your test framework supports it, you can alter a package variable within a test.
go example
This package defines OsCreate, a function that is used throghout the codebase.// internal/fs/fs.go package fs import "os" var OsCreate = os.Create // exported function, we can overrideIn our testfile, we swap OsCreate with one that returns an error
// foo_test.go package main import ( "errors" "foo.com/x/foo/internal/fs" ) func TestFoo(t *testing.T) { var ExpectedError = errors.New("Expected") fs.OsCreate = func(path string) (*os.File, error) { return nil, ExpectedError } foo.Foo() // <-- when foo calls 'fs.OsCreate', it will return expected error }