+Joel Stanley +Daniel Vetter If I remember correctly, both of you said you were interested in mocking on KUnit. This RFC only has some of the mocking features that I mentioned previously, but I would still like to get your thoughts. On Mon, Oct 12, 2020 at 3:21 PM Daniel Latypov <dlatypov@xxxxxxxxxx> wrote: > > # 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@xxxxxxxxxx/ > --- > > 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 >