Russell Bateman December 2014 last update:
The replacement of os.remove() is for the current process and only for the current process. If you don't restore the original function pointer when you are done, it's broken. Of course, it only matters if you are running a test suite and other tests would not expect the redirected function
''' Demonstration of stubbing/mocking. ''' import os class Foo( object ): def removeMe( self, path ): os.remove( path )
''' Demonstration, with foo.py, of how we can stub out os.remove(). ''' import unittest import os from foo import Foo class FooTest( unittest.TestCase ): def setUp( self ): # stub out os.remove() here self.os_remove_ori = os.remove os.remove = my_remove def tearDown( self ): os.remove = self.os_remove_ori def testRemoveFoo( self ): foo = Foo() foo.removeMe( "/path/filename" ) def my_remove( filepath ): print "Didn't actually try to remove ", filepath if __name__ == "__main__": unittest.main()
~ $ python Python 2.7.5 (default, Nov 3 2014, 14:26:24) [GCC 4.8.3 20140911 (Red Hat 4.8.3-7)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> class Foo( object ): ... def foo( self ): ... print 'foo' ... >>> from mock import patch >>> with patch.object( Foo, 'foo', autospec=True ) as mock_foo: ... mock_foo.return_value = 'bar' ... foo = Foo() ... foo.foo() ... 'bar'
>>> import mock >>> class Production( object ): ... def something( self ): ... print 'something' ... >>> real = Production() >>> real.something = mock.MagicMock() >>> real.something.return_value = 'changed' >>> real.something() 'changed'
In running a whole suite, the commented-out lines didn't work because they contaminated the definition of configuration.adjustConfigurationPath() for every test case after executing this one. Here's how to fix that problem. Note that
configuration.adjustConfigurationPath = configuration.adjustConfigurationPath()
...is just bad science anyway.
def testDATABASE_PATH_adjusted( self ): testUtilities.printTestCaseName( sys._getframe().f_code.co_name ) mockObtainPracticeList() setUpDatabaseMocks() databasePath = globals.DATABASE_PATH # rig configuration to give us what we want and not find what we don't want... createAndFillDummyConfigurationFile( 'sqlite:///../funny-place/appliance.db' ) # configuration.adjustConfigurationPath = Mock() # configuration.adjustConfigurationPath.return_value = CONFIGFILEPATH_FOR_TESTING p = patch( 'configuration.adjustConfigurationPath', new=MagicMock( return_value=CONFIGFILEPATH_FOR_TESTING ) ) p.start() testUtilities.spinCommandLine( testFodder.SIMPLE_PUBLISH_DEF % testUtilities.getRandomId() ) result = batch_runner.main( 'dummy' ) p.stop() # (demonstrate that our mock has gone away...) # asdf = configuration.adjustConfigurationPath( 'asdf' ) # configuration.adjustConfigurationPath = configuration.adjustConfigurationPath() assert globals.DATABASE_PATH != databasePath
Informed by: http://stackoverflow.com/questions/16310989/python-how-to-unmock-reset-mock-during-testing
Sort of a stupid example (since called with constants), but it illustrates the use of Mock.assert_called_with().
. . . def test( self ): install.wget = Mock() result = install.main( dummy='crap' ) install.wget.assert_called_with( url=install.ACTIVEMQ_TARBALL_URI, filename=install.TARBALL_NAME ) . . .
. . . try: wget( url=ACTIVEMQ_TARBALL_URI, filename=TARBALL_NAME ) . . .
Other Mock() methods include:
__init__( name, return_value, side_effect, spec ) reset_mock() assert_called_with( *args, **argkw ) assert_called_once_with( *args, **argkw ) assert_has_calls( ... ) assert_any_calls( *args, **argkw ) called : Boolean call_count : integer call_args : tuple call_args_list : list method_calls : list mock_calls : list