From: Daniel Latypov <dlatypov@google.com>
To: dlatypov@google.com
Cc: alan.maguire@oracle.com, brendanhiggins@google.com,
davidgow@google.com, keescook@chromium.org,
kunit-dev@googlegroups.com, linux-kernel@vger.kernel.org,
linux-kselftest@vger.kernel.org, mcgrof@kernel.org,
sboyd@kernel.org, skhan@linuxfoundation.org
Subject: [RFC v2 00/12] kunit: introduce class mocking support.
Date: Mon, 12 Oct 2020 15:20:38 -0700 [thread overview]
Message-ID: <20201012222050.999431-1-dlatypov@google.com> (raw)
# Background
KUnit currently lacks any first-class support for mocking.
For an overview and discussion on the pros and cons, see
https://martinfowler.com/articles/mocksArentStubs.html
This patch set introduces the basic machinery needed for mocking:
setting and validating expectations, setting default actions, etc.
Using that basic infrastructure, we add macros for "class mocking", as
it's probably the easiest type of mocking to start with.
## Class mocking
By "class mocking", we're referring mocking out function pointers stored
in structs like:
struct sender {
int (*send)(struct sender *sender, int data);
};
or in ops structs
struct sender {
struct send_ops *ops; // contains `send`
};
After the necessary DEFINE_* macros, we can then write code like
struct MOCK(sender) mock_sender = CONSTRUCT_MOCK(sender, test);
/* Fake an error for a specific input. */
handle = KUNIT_EXPECT_CALL(send(<omitted>, kunit_int_eq(42)));
handle->action = kunit_int_return(test, -EINVAL);
/* Pass the mocked object to some code under test. */
KUNIT_EXPECT_EQ(test, -EINVAL, send_message(...));
I.e. the goal is to make it easier to test
1) with less dependencies (we don't need to setup a real `sender`)
2) unusual/error conditions more easily.
In the future, we hope to build upon this to support mocking in more
contexts, e.g. standalone funcs, etc.
# TODOs
## Naming
This introduces a number of new macros for dealing with mocks,
e.g:
DEFINE_STRUCT_CLASS_MOCK(METHOD(foo), CLASS(example),
RETURNS(int),
PARAMS(struct example *, int));
...
KUNIT_EXPECT_CALL(foo(mock_get_ctrl(mock_example), ...);
For consistency, we could prefix everything with KUNIT, e.g.
`KUNIT_DEFINE_STRUCT_CLASS_MOCK` and `kunit_mock_get_ctrl`, but it feels
like the names might be long enough that they would hinder readability.
## Usage
For now the only use of class mocking is in kunit-example-test.c
As part of changing this from an RFC to a real patch set, we're hoping
to include at least one example.
Pointers to bits of code where this would be useful that aren't too
hairy would be appreciated.
E.g. could easily add a test for tools/perf/ui/progress.h, e.g. that
ui_progress__init() calls ui_progress_ops.init(), but that likely isn't
useful to anyone.
---
v2:
* Pass `struct kunit *` to mock init's to allow allocating ops structs.
* Update kunit-example-test.cc to do so as a more realistic example.
v1: https://lore.kernel.org/linux-kselftest/20200918183114.2571146-1-dlatypov@google.com/
---
Brendan Higgins (9):
kunit: test: add kunit_stream a std::stream like logger
kunit: test: add concept of post conditions
checkpatch: add support for struct MOCK(foo) syntax
kunit: mock: add parameter list manipulation macros
kunit: mock: add internal mock infrastructure
kunit: mock: add basic matchers and actions
kunit: mock: add class mocking support
kunit: mock: add struct param matcher
kunit: mock: implement nice, strict and naggy mock distinctions
Daniel Latypov (2):
Revert "kunit: move string-stream.h to lib/kunit"
kunit: expose kunit_set_failure() for use by mocking
Marcelo Schmitt (1):
kunit: mock: add macro machinery to pick correct format args
include/kunit/assert.h | 3 +-
include/kunit/kunit-stream.h | 94 +++
include/kunit/mock.h | 902 +++++++++++++++++++++++++
include/kunit/params.h | 305 +++++++++
{lib => include}/kunit/string-stream.h | 2 +
include/kunit/test.h | 9 +
lib/kunit/Makefile | 9 +-
lib/kunit/assert.c | 2 -
lib/kunit/common-mocks.c | 409 +++++++++++
lib/kunit/kunit-example-test.c | 98 +++
lib/kunit/kunit-stream.c | 110 +++
lib/kunit/mock-macro-test.c | 241 +++++++
lib/kunit/mock-test.c | 531 +++++++++++++++
lib/kunit/mock.c | 370 ++++++++++
lib/kunit/string-stream-test.c | 3 +-
lib/kunit/string-stream.c | 5 +-
lib/kunit/test.c | 15 +-
scripts/checkpatch.pl | 4 +
18 files changed, 3099 insertions(+), 13 deletions(-)
create mode 100644 include/kunit/kunit-stream.h
create mode 100644 include/kunit/mock.h
create mode 100644 include/kunit/params.h
rename {lib => include}/kunit/string-stream.h (95%)
create mode 100644 lib/kunit/common-mocks.c
create mode 100644 lib/kunit/kunit-stream.c
create mode 100644 lib/kunit/mock-macro-test.c
create mode 100644 lib/kunit/mock-test.c
create mode 100644 lib/kunit/mock.c
base-commit: 10b82d5176488acee2820e5a2cf0f2ec5c3488b6
--
2.28.0.1011.ga647a8990f-goog
next reply other threads:[~2020-10-12 22:21 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-10-12 22:20 Daniel Latypov [this message]
2020-10-12 22:20 ` [RFC v2 01/12] Revert "kunit: move string-stream.h to lib/kunit" Daniel Latypov
2020-10-12 22:20 ` [RFC v2 02/12] kunit: test: add kunit_stream a std::stream like logger Daniel Latypov
2020-10-12 22:20 ` [RFC v2 03/12] kunit: test: add concept of post conditions Daniel Latypov
2020-10-12 22:20 ` [RFC v2 04/12] checkpatch: add support for struct MOCK(foo) syntax Daniel Latypov
2020-10-12 22:20 ` [RFC v2 05/12] kunit: mock: add parameter list manipulation macros Daniel Latypov
2020-10-12 22:20 ` [RFC v2 06/12] kunit: expose kunit_set_failure() for use by mocking Daniel Latypov
2020-10-12 22:20 ` [RFC v2 07/12] kunit: mock: add internal mock infrastructure Daniel Latypov
2020-10-12 22:20 ` [RFC v2 08/12] kunit: mock: add basic matchers and actions Daniel Latypov
2020-10-12 22:20 ` [RFC v2 09/12] kunit: mock: add macro machinery to pick correct format args Daniel Latypov
2020-10-12 22:20 ` [RFC v2 10/12] kunit: mock: add class mocking support Daniel Latypov
2020-10-12 22:20 ` [RFC v2 11/12] kunit: mock: add struct param matcher Daniel Latypov
2020-10-12 22:20 ` [RFC v2 12/12] kunit: mock: implement nice, strict and naggy mock distinctions Daniel Latypov
2020-11-02 18:00 ` [RFC v2 00/12] kunit: introduce class mocking support Brendan Higgins
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20201012222050.999431-1-dlatypov@google.com \
--to=dlatypov@google.com \
--cc=alan.maguire@oracle.com \
--cc=brendanhiggins@google.com \
--cc=davidgow@google.com \
--cc=keescook@chromium.org \
--cc=kunit-dev@googlegroups.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=mcgrof@kernel.org \
--cc=sboyd@kernel.org \
--cc=skhan@linuxfoundation.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).