Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Good way to isolate tests that depend on an initializer

I've really tried to start isolating my unit tests so I can pinpoint where errors occur rather than having my entire screen turn red with failures when one thing goes wrong. It's been working in all instances except when something in an initializer fails.

Check out these tests:

@setup_directory(test_path)
def test_filename(self):
  flexmock(lib.utility.time).should_receive('timestamp_with_random').and_return(1234)

  f = SomeFiles(self.test_path)
  assert f.path == os.path.join(self.test_path, '1234.db')

@setup_directory(test_path)
def test_filename_with_suffix(self):
  flexmock(lib.utility.time).should_receive('timestamp_with_random').and_return(1234)

  f = SomeFiles(self.test_path, suffix='.txt')
  assert f.path == os.path.join(self.test_path, '1234.txt')

I'm mocking dependent methods so that the thing I'm testing is completely isolated. What you notice is that the class needs to be instantiated for every single test. If an error is introduced in the initializer, every single test fails.

This is the offending constructor that calls the class's initializer:

SomeFiles(*args)

Is there a way to isolate or mock the initializer or object constructor?

like image 723
Bob Briski Avatar asked Nov 11 '22 20:11

Bob Briski


1 Answers

I'm not sure what testing packages you're using, but in general, you can usually just mock the __init__() call on the class before actually attempting to use it. Something like

def my_init_mock_fn(*args, **kwargs):
    print 'mock_init'

SomeFiles.__init__ = my_init_mock_fn
SomeFiles()

This isn't probably exactly what you want as from this point on SomeFiles.__init__ fn will always be the mock fn, but there are utilities like voidspace mock that provide a patch function that allow you to patch the class just for a specific scope.

from mock import patch
with patch.object(SomeFiles, '__init__', my_init_mock_fn):
    SomeFiles()
    ..other various tests...
SomeFiles() #__init__ is reset to original __init__ fn

I'm sure there's probably similar functionality in whatever mocking package you are using.

Just realized you're using flexmock, there's a page for replace_with here.

like image 123
Silfheed Avatar answered Nov 15 '22 00:11

Silfheed