Python automatic testing: mocking an imported module?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Silfheed

    #1

    Python automatic testing: mocking an imported module?

    Heyas

    So we have the following situation: we have a testee.py that we want
    to automatically test out and verifiy that it is worthy of being
    deployed. We want our tester.py to test the code for testee.py
    without changing the code for testee.py. testee.py has a module in it
    that we want to mock in some tests and in others use the real module.

    /foo.py: (real module)
    class bar:
    def __init__(self):
    "I am real"

    /foo_fake/foo.py: (fake module)
    class bar:
    def ___init__(self) :
    "I am a banana"

    /testee.py:
    import foo
    foo.bar()

    /tester.py:
    from foo_fake import foo
    foo.bar() # prints I am a banana
    testee.py # also prints I am a banana
    import foo
    foo.bar() # prints I am real
    testee.py # also prints I am real


    This isnt working as we would like, does anyone have any tips on how
    to get something like this working?

  • Chris Lasher

    #2
    Re: Python automatic testing: mocking an imported module?

    On Mar 27, 6:18 pm, "Silfheed" <silfh...@gmail .comwrote:
    Heyas
    >
    So we have the following situation: we have a testee.py that we want
    to automatically test out and verifiy that it is worthy of being
    deployed. We want our tester.py to test the code for testee.py
    without changing the code for testee.py. testee.py has a module in it
    that we want to mock in some tests and in others use the real module.
    I think you mean "testee.py *imports* a module", rather than "has a
    module in it". Semantics but I was thrown off by this at first.

    Why not write tests for the module that testee.py imports (here called
    "foo.py")? If you write out the tests and foo.py passes to spec, then
    you should feel confident it will work correctly with testee.py. Never
    trust it; always play paranoid coder, but feel comfortable enough
    using it.

    After all, why should you feel comfortable using modules in the
    standard library? Nobody guarantees bugs don't still lurk in there
    (heck, c.l.p just found one in pdb today), however, they have unit
    tests out the wazzoo that demonstrate, to the best of our knowledge,
    the module works to spec. If that approach is good enough for the
    standard library, wouldn't it be good enough for you?

    Chris

    Comment

    • Ben Finney

      #3
      Re: Python automatic testing: mocking an imported module?

      "Silfheed" <silfheed@gmail .comwrites:
      So we have the following situation: we have a testee.py that we want
      to automatically test out and verifiy that it is worthy of being
      deployed.
      This is sometimes called the "module under test". I wish there was a
      more succinct name in common usage.
      We want our tester.py to test the code for testee.py
      without changing the code for testee.py.
      This is called a "unit test" for the module.
      testee.py has a module in it
      Looking at your example, testee.py *imports* a module; it doesn't
      contain another one.
      that we want to mock in some tests and in othemodule.
      Excellent idea.


      ===== foo.py =====
      class Bar(object):
      def __init__(self):
      self.name = "bar"
      =====

      ===== dostuff.py =====
      import foo

      def get_bar():
      return foo.Bar()
      =====

      ===== test_dostuff.py =====
      import dostuff

      class Mock_foo_module (object):
      """ Mock object for foo module """

      class Bar(object):
      def __init__(self):
      self.name = "banana"

      def test_dostuff_ge t_bar_should_cr eate_bar():
      """ The dostuff.get_bar function should create a new Bar """
      dostuff.foo = Mock_foo_module ()
      test_bar = dostuff.get_bar ()
      if not test_bar.name == "banana":
      raise AssertionError( "test_bar.n ame should be banana")
      =====

      This is simply using an instance of a class (Mock_foo_modul e) to be a
      mock 'module' object. That mock module has the required 'Bar'
      attribute, bound to a class; so the 'dostuff' module's 'foo' attribute
      can be replaced with our mock module object for the purpose of the
      test.

      The mock module's Bar class behaves in an idiomatic way (setting the
      'name' attribute of its instance to a known value) that we use to
      check whether the 'dostuff' module actually used our mock module.

      This can be extended to mock any module interface you like, and then
      confirm that the module under test has actually used the module as
      expected.

      --
      \ "A politician is an animal which can sit on a fence and yet |
      `\ keep both ears to the ground." -- Henry L. Mencken |
      _o__) |
      Ben Finney

      Comment

      • Peter Otten

        #4
        Re: Python automatic testing: mocking an imported module?

        Silfheed wrote:
        So we have the following situation: we have a testee.py that we want
        to automatically test out and verifiy that it is worthy of being
        deployed. We want our tester.py to test the code for testee.py
        without changing the code for testee.py. testee.py has a module in it
        that we want to mock in some tests and in others use the real module.
        >
        /foo.py: (real module)
        class bar:
        def __init__(self):
        "I am real"
        >
        /foo_fake/foo.py: (fake module)
        class bar:
        def ___init__(self) :
        "I am a banana"
        >
        /testee.py:
        import foo
        foo.bar()
        >
        /tester.py:
        from foo_fake import foo
        foo.bar() # prints I am a banana
        testee.py # also prints I am a banana
        import foo
        foo.bar() # prints I am real
        testee.py # also prints I am real
        >
        >
        This isnt working as we would like, does anyone have any tips on how
        to get something like this working?
        You can put foo_fake.foo into sys.modules as foo:

        import sys
        from foo_fake import foo

        assert "foo" not in sys.modules
        sys.modules["foo"] = foo

        foo.bar() # prints I am a banana
        import foo
        foo.bar() # prints I am a banana

        Peter

        Comment

        • Mark T

          #5
          Re: Python automatic testing: mocking an imported module?


          "Silfheed" <silfheed@gmail .comwrote in message
          news:1175033934 .795913.292030@ l77g2000hsb.goo glegroups.com.. .
          Heyas
          >
          So we have the following situation: we have a testee.py that we want
          to automatically test out and verifiy that it is worthy of being
          deployed. We want our tester.py to test the code for testee.py
          without changing the code for testee.py. testee.py has a module in it
          that we want to mock in some tests and in others use the real module.
          >
          /foo.py: (real module)
          class bar:
          def __init__(self):
          "I am real"
          >
          /foo_fake/foo.py: (fake module)
          class bar:
          def ___init__(self) :
          "I am a banana"
          >
          /testee.py:
          import foo
          foo.bar()
          >
          /tester.py:
          from foo_fake import foo
          foo.bar() # prints I am a banana
          testee.py # also prints I am a banana
          import foo
          foo.bar() # prints I am real
          testee.py # also prints I am real
          >
          >
          This isnt working as we would like, does anyone have any tips on how
          to get something like this working?
          >
          If you add the foo_fake directory to the front of sys.path, "import foo"
          will import the foo.py in foo_fake directory before the one in the local
          directory.

          # unverified code
          import sys
          sys.path.append (0,'foo_fake') # add foo_fake to front of path
          import foo
          foo.bar()
          execfile('teste e.py')
          sys.path.pop(0) # remove foo_fake
          reload(foo)
          foo.bar()
          execfile('teste e.py')

          -Mark

          Comment

          • rocky.bernstein@gmail.com

            #6
            Re: Python automatic testing: mocking an imported module?

            On Mar 27, 9:13 pm, "Chris Lasher" <chris.las...@g mail.comwrote:
            On Mar 27, 6:18 pm, "Silfheed" <silfh...@gmail .comwrote:
            >
            Heyas
            >
            So we have the following situation: we have a testee.py that we want
            to automatically test out and verifiy that it is worthy of being
            deployed. We want our tester.py to test the code for testee.py
            without changing the code for testee.py. testee.py has a module in it
            that we want to mock in some tests and in others use the real module.
            >
            I think you mean "testee.py *imports* a module", rather than "has a
            module in it". Semantics but I was thrown off by this at first.
            >
            Why not write tests for the module that testee.py imports (here called
            "foo.py")? If you write out the tests and foo.py passes to spec, then
            you should feel confident it will work correctly with testee.py. Never
            trust it; always play paranoid coder, but feel comfortable enough
            using it.
            >
            After all, why should you feel comfortable using modules in the
            standard library? Nobody guarantees bugs don't still lurk in there
            (heck, c.l.p just found one inpdbtoday),
            A slight correction. At present it looks like the bug is in Python,
            and its handling after setting the current frame's f_lineno when it
            refers to byte code offset 0, not pdb. And if you scan c.l.p for
            another oddity in pdb with respect to tracebacks, there is possibly
            another bug in Python (not strictly pdb).
            however, they have unit
            tests out the wazzoo that demonstrate, to the best of our knowledge,
            the module works to spec.
            Actually, as far as I know pdb *doesn't* have any unit tests! (pydb
            does though ;-)

            But all this nit-picking aside, I do agree with what you have to say
            most whole heartedly. (And I'd say maybe a couple more unit tests for
            Python to cover these bugs are in order.)
            If that approach is good enough for the
            standard library, wouldn't it be good enough for you?
            >
            Chris

            Comment

            • Silfheed

              #7
              Re: Python automatic testing: mocking an imported module?

              Wow, that works great! Thanks all!

              On Mar 28, 12:02 am, Ben Finney <bignose+hate s-s...@benfinney. id.au>
              wrote:
              "Silfheed" <silfh...@gmail .comwrites:
              ===== foo.py =====
              class Bar(object):
              def __init__(self):
              self.name = "bar"
              =====
              >
              ===== dostuff.py =====
              import foo
              >
              def get_bar():
              return foo.Bar()
              =====
              >
              ===== test_dostuff.py =====
              import dostuff
              >
              class Mock_foo_module (object):
              """ Mock object for foo module """
              >
              class Bar(object):
              def __init__(self):
              self.name = "banana"
              >
              def test_dostuff_ge t_bar_should_cr eate_bar():
              """ The dostuff.get_bar function should create a new Bar """
              dostuff.foo = Mock_foo_module ()
              test_bar = dostuff.get_bar ()
              if not test_bar.name == "banana":
              raise AssertionError( "test_bar.n ame should be banana")
              =====
              >
              This is simply using an instance of a class (Mock_foo_modul e) to be a
              mock 'module' object. That mock module has the required 'Bar'
              attribute, bound to a class; so the 'dostuff' module's 'foo' attribute
              can be replaced with our mock module object for the purpose of the
              test.
              >
              The mock module's Bar class behaves in an idiomatic way (setting the
              'name' attribute of its instance to a known value) that we use to
              check whether the 'dostuff' module actually used our mock module.
              >
              This can be extended to mock any module interface you like, and then
              confirm that the module under test has actually used the module as
              expected.
              >
              --
              \ "A politician is an animal which can sit on a fence and yet |
              `\ keep both ears to the ground." -- Henry L. Mencken |
              _o__) |
              Ben Finney

              Comment

              Working...