unit testing with mocks

Post on 25-May-2015

2.082 Views

Category:

Technology

3 Downloads

Preview:

Click to see full reader

DESCRIPTION

June 13th, 2009 - CPyUG (China Python User Group)

TRANSCRIPT

Unit Testing with Mocksnasi

http://twitter.com/nasiless

Introducing Myself

Architect

Editor

Translator

Unit Testing

A World ...without Unit Testing

Verify

Design

Document

Regression

Edit & Pray

Cover & Modify

Python: unittest Moduleimport unittest

class MyTestCase(unittest.TestCase): def test1(self): """Run test 1""" pass

def test2(self): """Run test 2""" pass

if __name__ == '__main__': unittest.main()

Common unittest Methods

• assertTrue / assertFalse

• assertEquals

• assertRaises

• etc. • setUp

• tearDown

A test is not a unit test if:

• It talks to a database.

• It communicates across a network.

• It touches the file system.

-- Working Effectively with Legacy Code

how ?!

You need mock objects

• pMock (based on jMock)http://pmock.sourceforge.net/

• pyMock (based on EasyMock)http://theblobshop.com/pymock/

• minimock / mock / mox / mocker / ...

Mock Frameworks in Python:

Introducing fudge

• Domain Specific Language

• Powerful Patcher Built-in

• Expect something, Verify it

• Still Alive

http://farmdev.com/projects/fudge

common coding style for testing with mock objects

(1) Create instances of mock objectsmock = fudge.Fake('mock')

(2) Set state and expectations in the mock objectsmock.expects('method') \ .with_args(arg1=1, arg2='2').returns(True)

(3) Invoke domain code with mock objects as parametersmock.method(arg1=1, arg2='2')

(4) Verify consistency in the mock objectsfudge.verify()

Examples

Testing Databaseimport MySQLdb

def Foo(): conn = MySQLdb.connect(host='localhost', user='root', db='test') cursor = conn.cursor()

cursor.execute('SELECT * FROM people') id, name = cursor.fetchone() print id, name

if __name__ == '__main__': Foo()

Mock Databaseimport fudgefrom testmod import Foo

mysqldb = fudge.Fake('MySQLdb')

conn = mysqldb.expects('connect').returns_fake()curs = conn.provides('cursor').returns_fake()curs = curs.expects('execute').returns(1)curs = curs.provides('fetchone').returns((1, 'Nathan'))

@fudge.with_fakes@fudge.with_patched_object('testmod', 'MySQLdb', mysqldb)def Test(): Foo() # prints: 1 Nathan

if __name__ == '__main__': Test()

Testing Network

import urllib2

def Foo(): print urllib2.urlopen('http://www.google.com/').read()

if __name__ == '__main__': Foo()

Mock Networkimport fudgefrom cStringIO import StringIOfrom testmod import Foo

urlopen = fudge.Fake('urlopen', callable=True) \ .returns(StringIO('HelloWorld'))

@fudge.with_fakes@fudge.with_patched_object('urllib2', 'urlopen', urlopen)def Test(): Foo() # prints: HelloWorld

if __name__ == '__main__': Test()

Testing File System

import os

def Foo(): print os.listdir('.') open('a.txt', 'w').write('HelloWorld')

if __name__ == '__main__': Foo()

Mock File Systemimport fudgefrom cStringIO import StringIOfrom testmod import Foo

listdir = fudge.Fake(callable=True).returns(['a.txt', 'b.jpg'])buf = StringIO()myopen = lambda filename, mode: buf

@fudge.with_fakes@fudge.with_patched_object('os', 'listdir', listdir)@fudge.with_patched_object('__builtin__', 'open', myopen)def Test(): Foo() # prints: ['a.txt', 'b.jpg'] print buf.getvalue() # prints: HelloWorld

if __name__ == '__main__': Test()

Pros and Cons

Q & A

top related