[sheepdog] [PATCH v2 2/4] tests/unit: introduce mock

Kai Zhang kyle at zelin.io
Wed Jul 10 14:02:46 CEST 2013


Mock is useful when we do unit test.

This patch introduce some useful macro to simply testing.

The two most useful macro are MOCK_METHOD and MOCK_VOID_METHOD.

MOCK_VOID_METHOD is used to mock method how has no return value.
For example:
void foo(int a, long b)
{
	return;
}

We define the mock method as:
MOCK_VOID_METHOD(foo, int a, long b)

MOCK_METHOD is used to mock method how has return value.
User have to specified the return value's type and the default return value.
For example:
bool foo(int a, long b)
{
	return true;
}

We define the mock method as:
MOCK_METHCO(foo, bool, true, int a, long b)

Use macro to define mock method has many benifits:
- we can record each call of the method and its arguments
- we can control the return value, based on input arguments

However, current implementation is quite initial.
We just record how many times the method is called.

Another useful macro is METHOD_NR_CALL which returns how many times the method
is called.

Signed-off-by: Kai Zhang <kyle at zelin.io>
---
 configure.ac                |    1 +
 tests/unit/Makefile.am      |    2 +-
 tests/unit/mock/Makefile.am |    7 ++++++
 tests/unit/mock/mock.c      |   41 ++++++++++++++++++++++++++++++
 tests/unit/mock/mock.h      |   58 +++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 108 insertions(+), 1 deletion(-)
 create mode 100644 tests/unit/mock/Makefile.am
 create mode 100644 tests/unit/mock/mock.c
 create mode 100644 tests/unit/mock/mock.h

diff --git a/configure.ac b/configure.ac
index b609fac..84ce448 100644
--- a/configure.ac
+++ b/configure.ac
@@ -136,6 +136,7 @@ AC_CONFIG_FILES([Makefile
 		man/Makefile
 		shepherd/Makefile
 		tests/unit/Makefile
+		tests/unit/mock/Makefile
 		tests/unit/collie/Makefile
 		tests/unit/sheep/Makefile
 		tools/Makefile])
diff --git a/tests/unit/Makefile.am b/tests/unit/Makefile.am
index eb0a50e..3e6255a 100644
--- a/tests/unit/Makefile.am
+++ b/tests/unit/Makefile.am
@@ -1,3 +1,3 @@
 MAINTAINERCLEANFILES	= Makefile.in
 
-SUBDIRS			= collie sheep
+SUBDIRS			= mock collie sheep
diff --git a/tests/unit/mock/Makefile.am b/tests/unit/mock/Makefile.am
new file mode 100644
index 0000000..b7c0c32
--- /dev/null
+++ b/tests/unit/mock/Makefile.am
@@ -0,0 +1,7 @@
+MAINTAINERCLEANFILES    = Makefile.in
+
+INCLUDES                = -I$(top_builddir)/include -I$(top_srcdir)/include
+
+noinst_LIBRARIES	= libmock.a
+
+libmock_a_SOURCES	= mock.c
diff --git a/tests/unit/mock/mock.c b/tests/unit/mock/mock.c
new file mode 100644
index 0000000..11f68b8
--- /dev/null
+++ b/tests/unit/mock/mock.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2013 Zelin.io
+ *
+ * Kai Zhang <kyle at zelin.io>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+
+#include "list.h"
+#include "logger.h"
+#include "mock.h"
+
+LIST_HEAD(mock_methods);
+
+static struct mock_method *find_method(const char *name)
+{
+	struct mock_method *method;
+	int len;
+	list_for_each_entry(method, &mock_methods, list) {
+		len = strlen(method->name);
+		if (strncmp(method->name, name, len) == 0)
+			return method;
+	}
+	return NULL;
+}
+
+int __method_nr_call(const char *name)
+{
+	struct mock_method *method = find_method(name);
+	if (method)
+		return method->nr_call;
+	else
+		panic("%s is not a mock method", name);
+}
diff --git a/tests/unit/mock/mock.h b/tests/unit/mock/mock.h
new file mode 100644
index 0000000..cdb3249
--- /dev/null
+++ b/tests/unit/mock/mock.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2013 Zelin.io
+ *
+ * Kai Zhang <kyle at zelin.io>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MOCK_H__
+#define __MOCK_H__
+
+#include "list.h"
+
+struct mock_method {
+	const char *name;
+	int nr_call;
+	struct list_head list;
+};
+
+extern struct list_head mock_methods;
+#define method_register(m)						\
+	static void __attribute__((constructor)) regist_##m(void)	\
+	{								\
+		list_add(&m.list, &mock_methods);			\
+	}
+
+#define MOCK_VOID_METHOD(m, ...)			\
+	static struct mock_method _##m = {		\
+		.name = #m,				\
+	};						\
+	void m(__VA_ARGS__)				\
+	{						\
+		_##m.nr_call++;				\
+			return;				\
+	}						\
+	method_register(_##m)
+
+#define MOCK_METHOD(m, rt, rv, ...)			\
+	static struct mock_method _##m = {		\
+		.name = #m,				\
+	};						\
+	rt m(__VA_ARGS__)				\
+	{						\
+		_##m.nr_call++;				\
+			return rv;			\
+	}						\
+	method_register(_##m)
+
+int __method_nr_call(const char *name);
+
+#define METHOD_NR_CALL(m) __method_nr_call(#m)
+
+#endif
-- 
1.7.9.5




More information about the sheepdog mailing list