Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #95347 > unrolled thread

Mock object but also assert method calls?

Started byThomas Lehmann <thomas.lehmann.private@googlemail.com>
First post2015-08-13 08:58 -0700
Last post2015-08-15 04:07 -0700
Articles 4 — 3 participants

Back to article view | Back to comp.lang.python


Contents

  Mock object but also assert method calls? Thomas Lehmann <thomas.lehmann.private@googlemail.com> - 2015-08-13 08:58 -0700
    Re: Mock object but also assert method calls? Ben Finney <ben+python@benfinney.id.au> - 2015-08-14 07:21 +1000
      Re: Mock object but also assert method calls? Steven D'Aprano <steve@pearwood.info> - 2015-08-14 12:53 +1000
        Re: Mock object but also assert method calls? Thomas Lehmann <thomas.lehmann.private@googlemail.com> - 2015-08-15 04:07 -0700

#95347 — Mock object but also assert method calls?

FromThomas Lehmann <thomas.lehmann.private@googlemail.com>
Date2015-08-13 08:58 -0700
SubjectMock object but also assert method calls?
Message-ID<509adc48-996d-44b0-abf1-e15ee387023b@googlegroups.com>
Hi,

How about asserting that test2 of class Bar is called?
Of course I can do a patch for a concrete method but
I was looking for something like:

    mocked_object.assert_method_called_with(name="test2", "hello")

If find following totally different to the normal API which
is provided by the mock library:

assert call().test2("hello") in mocked_objects.mock_calls

Is there a better way?

APPENDIX:
Foo delegates calls to Bar.

[code]
    from mock import patch
    with patch("__main__.Bar") as mocked_object:
        foo = Foo()
        foo.test1()
        foo.test2("hello")
        print(mocked_object.mock_calls)
        # print all calls (c'tor as well as normal methods)
        for name, args, kwargs in mocked_object.mock_calls:
            print(name, args, kwargs)
[/code]

Generates:

<class '__main__.Bar'>
test1: Foo has been called
test2: Foo has been called with value hello
[call(), call().test1(), call().test2('hello')]
('', (), {})
('().test1', (), {})
('().test2', ('hello',), {})

[toc] | [next] | [standalone]


#95358

FromBen Finney <ben+python@benfinney.id.au>
Date2015-08-14 07:21 +1000
Message-ID<mailman.178.1439500927.3627.python-list@python.org>
In reply to#95347
Thomas Lehmann via Python-list <python-list@python.org> writes:

> How about asserting that test2 of class Bar is called?

It is unusual to call class methods; do you mean a method on an
instance?

You will make a mock instance of the class, or a mock of the class; and
you'll need to know which it is.

> Of course I can do a patch for a concrete method but I was looking for
> something like:
>
>     mocked_object.assert_method_called_with(name="test2", "hello")

The ‘mock’ library defaults to providing ‘MagicMock’, which is “magic”
in the sense that it automatically provides any attribute you request,
and those attributes are themselves also MagicMocks::

    import unittest.mock

    def test_spam_calls_foo_bar():
        """ Should call the `spam` method on the specified `Foo` instance. """
        mock_foo = unittest.mock.MagicMock(system_under_test.Foo)
        system_under_test.spam(mock_foo)
        mock_foo.spam.assert_called_with("hello")

> If find following totally different to the normal API which
> is provided by the mock library:
>
> assert call().test2("hello") in mocked_objects.mock_calls

The ‘assert’ statement is a crude tool, which knows little about the
intent of your assertion. You should be instead using the specialised
methods from ‘unittest.TestCase’ and the methods on the mock objects
themselves.

-- 
 \       “It is the mark of an educated mind to be able to entertain a |
  `\                         thought without accepting it.” —Aristotle |
_o__)                                                                  |
Ben Finney

[toc] | [prev] | [next] | [standalone]


#95368

FromSteven D'Aprano <steve@pearwood.info>
Date2015-08-14 12:53 +1000
Message-ID<55cd5839$0$1636$c3e8da3$5496439d@news.astraweb.com>
In reply to#95358
On Fri, 14 Aug 2015 07:21 am, Ben Finney wrote:

>> If find following totally different to the normal API which
>> is provided by the mock library:
>>
>> assert call().test2("hello") in mocked_objects.mock_calls
> 
> The ‘assert’ statement is a crude tool, which knows little about the
> intent of your assertion.

I agree with Ben here. Despite the popularity of "nose" (I think it is
nose?) which uses `assert` for testing, I think that is a gross misuse of
the statement. It is okay to use assertions this way for quick and dirty ad
hoc testing, say at the command line, but IMO totally inappropriate for
anything more formal, like unit testing.

If for no other reason than the use of `assert` for testing makes it
impossible to test your code when running with the Python -O (optimize)
switch.

For more detail on the uses, and abuses, of `assert` see this:

http://import-that.dreamwidth.org/676.html


-- 
Steven

[toc] | [prev] | [next] | [standalone]


#95391

FromThomas Lehmann <thomas.lehmann.private@googlemail.com>
Date2015-08-15 04:07 -0700
Message-ID<cca7ce43-bed9-48a9-959a-341b17e5cebf@googlegroups.com>
In reply to#95368
Am Freitag, 14. August 2015 04:53:56 UTC+2 schrieb Steven D'Aprano:
> On Fri, 14 Aug 2015 07:21 am, Ben Finney wrote:
> 
> >> If find following totally different to the normal API which
> >> is provided by the mock library:
> >>
> >> assert call().test2("hello") in mocked_objects.mock_calls
> > 
> > The 'assert' statement is a crude tool, which knows little about the
> > intent of your assertion.
> 
> I agree with Ben here. Despite the popularity of "nose" (I think it is
> nose?) which uses `assert` for testing, I think that is a gross misuse of
> the statement. It is okay to use assertions this way for quick and dirty ad
> hoc testing, say at the command line, but IMO totally inappropriate for
> anything more formal, like unit testing.
> 
> If for no other reason than the use of `assert` for testing makes it
> impossible to test your code when running with the Python -O (optimize)
> switch.
> 
> For more detail on the uses, and abuses, of `assert` see this:
> 
Of course you do NOT use assert in unit tests but I provided
just test code to show my problem. Of course I take nose and
hamcrest and code coverage ...

Here a complete example of my problem (with comments):


from mock import MagicMock, call, patch

class Bla:
    def test1(self, value):
        pass
    
mocked_object = MagicMock(Bla)
bla = Bla()
bla.test1("hello")
# empty, why?
print(mocked_object.mock_calls)
# does not work: mocked_object.test1.assert_called_with("hello")

with patch("__main__.Bla") as mocked_object:
    bla = Bla()
    bla.test1("hello")
    # not empty!
    print(mocked_object.mock_calls)
    # does also not work: mocked_object.test1.assert_called_with("hello")
    # but this does work:
    assert call().test1("hello") in mocked_object.mock_calls


I don't wanna patch each individual method. Is there no other way?

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web