Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.1/25



Similar documents
CIS 192: Lecture 13 Scientific Computing and Unit Testing

Python for Test Automation i. Python for Test Automation

Survey of Unit-Testing Frameworks. by John Szakmeister and Tim Woods

SQL Injection Vulnerabilities in Desktop Applications

Software Testing with Python

Intro to scientific programming (with Python) Pietro Berkes, Brandeis University

Python as a Testing Tool. Chris Withers

Effective unit testing with JUnit

Open source framework for interactive data exploration in server based architecture

socketio Documentation

Advanced Tornado TWENTYONE Advanced Tornado Accessing MySQL from Python LAB

Testing Providers with PyWBEM

Python Dependency Injection

Grinder Webtest Documentation

Version Control Your Jenkins Jobs with Jenkins Job Builder

Python Testing with unittest, nose, pytest

Advanced Web Security, Lab

CYAN SECURE WEB APPLIANCE. User interface manual

Sitecore Health. Christopher Wojciech. netzkern AG. Sitecore User Group Conference 2015

SysPatrol - Server Security Monitor

SELF SERVICE RESET PASSWORD MANAGEMENT DATABASE REPLICATION GUIDE

Wrestling with Python Unit testing. Warren Viant

latest Release 0.2.6

Configuring Logging. Configuring application logging with the LoggingConfigurator class.

Advanced Topics: Biopython

SNMP-1 Configuration Guide

New Tools for Testing Web Applications with Python

Best Practices for Building Splunk Apps and Technology Add-ons

Writing robust scientific code with testing (and Python) Pietro Berkes, Enthought UK

Python for Rookies. Example Examination Paper

There are numerous ways to access monitors:

Setting cron job Linux/Unix operating systems using command-line interface

White Paper March 1, Integrating AR System with Single Sign-On (SSO) authentication systems

SITRANS RD500 Configuring the RD500 with PSTN or GSM modems and Windows-based servers and clients for communication Objective:

Server-side Development using Python and SQL

Z Documentation. Release 2. Bart Thate

Test Driven Development in Python

How to establish a Leased Line Connection

Toad for Oracle 8.6 SQL Tuning

AUTOMATIC DETECTION OF VULNERABILITY IN WRAPPED PACKAGES IN ORACLE

BS1000 command and backlog protocol

Tutorial IV: Unit Test

Objects and classes. Objects and classes. Jarkko Toivonen (CS Department) Programming in Python 1

Sophos for Microsoft SharePoint Help

1. Stem. Configuration and Use of Stem

PROJECT REPORT OF BUILDING COURSE MANAGEMENT SYSTEM BY DJANGO FRAMEWORK

Python for Test Automation i. Python for Test Automation

APPLICATION NOTE. CC5MPX Digital Camera and IPn3Gb Cellular Modem 10/14. App. Note Code: 3T-Z

Synthetic Application Monitoring

How to Secure a Groove Manager Web Site

Java EE Web Development Course Program

Dry Dock Documentation

Things you didn't know about Python

CoreLib Documentation

Developing tests for the KVM autotest framework

Integrity Checking and Monitoring of Files on the CASTOR Disk Servers

ft6 Motivation next step: perform the tests usually tedious, error prone work aided by a tool easily repeatable enter ft6 ft6

New and Improved Lustre Performance Monitoring Tool. Torben Kling Petersen, PhD Principal Engineer. Chris Bloxham Principal Architect

How to Configure Outlook Client for Exchange

Rapid Website Deployment With Django, Heroku & New Relic

Rake Task Management Essentials

Improved metrics collection and correlation for the CERN cloud storage test framework

Tutorial. Reference for more thorough Mininet walkthrough if desired

Gillcup Documentation

Survey of the Benchmark Systems and Testing Frameworks For Tachyon-Perf

Automating SQL Injection Exploits

IP Phone Service Administration and Subscription

SAPIP GUI INSTALLATION. Table of Contents

Enterprise Content Management System Monitor. Server Debugging Guide CENIT AG Bettighofer, Stefan

CoCreate Manager Server Installation Guide. CoCreate Manager Server Installation Guide 1

flask-mail Documentation

Unit Testing. and. JUnit

Healthstone Monitoring System

Summer Internship 2013

Sophos for Microsoft SharePoint Help. Product version: 2.0

NiCE Log File Management Pack. for. System Center Operations Manager Quick Start Guide

A Walk Around the SQL Server 2012 Audit Feature. Timothy P. McAliley Microsoft Premier Field Engineer SQL Server

Training and Certification Guide - Navision

SpiraTest / SpiraTeam Automated Unit Testing Integration & User Guide Inflectra Corporation

MS SQL Express installation and usage with PHMI projects

Software Tool Seminar WS Taming the Snake

Send TLM. Table of contents

SMock A Test Platform for the Evaluation of Monitoring Tools

DiskBoss. File & Disk Manager. Version 2.0. Dec Flexense Ltd. info@flexense.com. File Integrity Monitor

Analyzing Network Servers. Disk Space Utilization Analysis. DiskBoss - Data Management Solution

Pyak47 - Performance Test Framework. Release 1.2.1

Setting Up the Site Licenses

Perceptive Intelligent Capture Solution Configration Manager

Understanding MySQL storage and clustering in QueueMetrics. Loway

Extending Legacy Applications to Consume Web Services. OpenSpan White Paper Series: Extending Legacy Applications to Consume Web Services

Writing Self-testing Java Classes with SelfTest

Moving from CS 61A Scheme to CS 61B Java

smtplib SMTP protocol client

NovaBACKUP xsp Version 15.0 Upgrade Guide

Software Testing. Theory and Practicalities

Transcription:

Unit testing with mock code EuroPython 2004 Stefan Schwarzer sschwarzer@sschwarzer.net Informationsdienst Wissenschaft e. V. Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.1/25

Personal background I m leading the software development at the Informationsdienst Wissenschaft e. V. (idw, Science Information Service), http://idw-online.de The idw distributes press releases of scientific institutions to the public, but especially to journalists The idw software is currently rewritten (approx. 50 000 lines of Python code, 10 000 for unit tests) I wrote a book, Workshop Python (Addison-Wesley) Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.2/25

Overview A glance at the unittest.testcase class Definitions Typical mock object usage Example 1: A logging mock object Example 2: Testing a Logfile class with mock code Some tips for mock code usage Testing at the right call level When to use mock code Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.3/25

Testing with unittest.testcase import unittest class MyTestCase(unittest.TestCase): def test1(self,...): "Run test 1"... def test2(self,...): "Run test 2"... if name == main : unittest.main() Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.4/25

Some common TestCase methods Does the code to test behave as expected? assertequal(arg1, arg2) assertraises(exception_type, callable_, *args, **kwargs) failif(condition) failunless(condition) How do we isolate the test methods from each other? setup() teardown() Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.5/25

Definitions Code under test is the part of the production code we want to test by writing some test code Mock code is substitute code for production code which is used by the code under test A mock object is mock code in form of an object A difficult test is a unit test that suggests using mock code (see next page) Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.6/25

Difficult tests We want to test if our code behaves correctly, but... we can t reproduce something because it s not under our control the setup of the test fixture would be possible but difficult, slow or error-prone Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.7/25

Difficult tests We want to test if our code behaves correctly, but... we can t reproduce something because it s not under our control the setup of the test fixture would be possible but difficult, slow or error-prone Examples: A file system becomes full while writing a file An internet connection is lost during a data transfer A mail server can t be reached Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.7/25

Difficult tests We want to test if our code behaves correctly, but... we can t reproduce something because it s not under our control the setup of the test fixture would be possible but difficult, slow or error-prone Examples: A file system becomes full while writing a file An internet connection is lost during a data transfer A mail server can t be reached Use mock code for difficult tests Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.7/25

Typical mock object usage The test code... 1. prepares the mock object to show a certain behavior when it is used Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.8/25

Typical mock object usage The test code... 1. prepares the mock object to show a certain behavior when it is used 2. calls the code under test, passing in the mock object as an argument Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.8/25

Typical mock object usage The test code... 1. prepares the mock object to show a certain behavior when it is used 2. calls the code under test, passing in the mock object as an argument 3. checks the mock object for signs of its usage by the code under test Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.8/25

A logging mock object (1) class Logger: def init (self): # don t trigger setattr self. dict [ history ] = [] def setattr (self, attrname, value): self.history.append( "Set attribute %s to %r" % (attrname, value)) def getattr (self, attrname): self.history.append( "Read attribute %s" % attrname) Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.9/25

A logging mock object (2) def test_code(an_object): an_object.x = 9 y = an_object.x logger = Logger() test_code(logger) for event in logger.history: print event Output: Set attribute x to 9 Read attribute x Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.10/25

A Logfile class The class wraps a file-like object; the constructor gets it as the argument: logfile = Logfile(wrapped_file) On writing, the write method adds the current timestamp in front of the string to write. With wrapped_file = file("myapp.log", "w") logfile = Logfile(wrapped_file) logfile.write("test") we may get in the wrapped file 2004-06-07 09:32:25 Test Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.11/25

A Logfile class implementation class Logfile: def init (self, wrapped_file): self.wrapped = wrapped_file def write(self, message): self.wrapped.write("%s %s\n" % (self.timestamp(), message)) def timestamp(self): return time.strftime( "%Y-%m-%d %H:%M:%S") Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.12/25

Testing Logfile s write method Python s StringIO objects are natural mock objects They make it easy to test code that uses arbitrary file-like objects No filesystem needed; no cleanup after writing the file ; written data is easily accessible Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.13/25

Testing Logfile s write method Python s StringIO objects are natural mock objects They make it easy to test code that uses arbitrary file-like objects No filesystem needed; no cleanup after writing the file ; written data is easily accessible Test code for Logfile.write: wrapped = StringIO.StringIO() logfile = Logfile(wrapped) logfile.write("test message") contents = wrapped.getvalue() # check format of contents (a bit tedious)... Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.13/25

Simplify the format check (1) Modify the original Logfile class: class Logfile:... def timestamp(self): return time.strftime( "%Y-%m-%d %H:%M:%S", self._time_tuple()) def _time_tuple(self): return time.localtime() Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.14/25

Simplify the format check (2) Derive from the Logfile class; inject mock code class MyLogfile(Logfile): def _time_tuple(self): return (2004, 6, 7, 10, 20, 30, 0, 0, -1) Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.15/25

Simplify the format check (2) Derive from the Logfile class; inject mock code class MyLogfile(Logfile): def _time_tuple(self): return (2004, 6, 7, 10, 20, 30, 0, 0, -1) Use the modified class in the test wrapped = StringIO.StringIO() logfile = MyLogfile(wrapped) logfile.write("test message") self.assertequal(wrapped.getvalue(), "2004-06-07 10:20:30 Test message\n") Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.15/25

Simplify the format check (2) Derive from the Logfile class; inject mock code class MyLogfile(Logfile): def _time_tuple(self): return (2004, 6, 7, 10, 20, 30, 0, 0, -1) Use the modified class in the test wrapped = StringIO.StringIO() logfile = MyLogfile(wrapped) logfile.write("test message") self.assertequal(wrapped.getvalue(), "2004-06-07 10:20:30 Test message\n") Mask only trivial code under test with mock code Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.15/25

Testing exception handling (1) Assume a Logfile object should raise a LogError if the write method of the underlying file-like object fails with an IOError Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.16/25

Testing exception handling (2) Possible implementation class LogError(Exception): pass class Logfile:... def write(self, message): try: self.wrapped.write("%s %s\n" % (self.timestamp(), message)) except IOError: raise LogError("IO error") Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.17/25

Testing exception handling (3) This implementation is easy to check with a mock object class FailingFile: def write(self, message): raise IOError("failing mock object") Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.18/25

Testing exception handling (3) This implementation is easy to check with a mock object class FailingFile: def write(self, message): raise IOError("failing mock object") Test code: wrapped_file = FailingFile() logfile = Logfile(wrapped_file) self.assertraises(logerror, logfile.write, "Test") Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.18/25

Tips for using mock code Typical mock objects are connection objects of all kinds (database, HTTP, SMTP,...), files and file-like objects Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.19/25

Tips for using mock code Typical mock objects are connection objects of all kinds (database, HTTP, SMTP,...), files and file-like objects Inject mock code... as mock objects passed into production code functions or methods via an overwritten method in the production code class (this method may be a factory which returns a production code or a mock object) Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.19/25

Tips for using mock code Typical mock objects are connection objects of all kinds (database, HTTP, SMTP,...), files and file-like objects Inject mock code... as mock objects passed into production code functions or methods via an overwritten method in the production code class (this method may be a factory which returns a production code or a mock object) Keep your mock code simple. Avoid coding universal mock objects; they can become rather complicated and difficult to maintain Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.19/25

Tips for using mock code Typical mock objects are connection objects of all kinds (database, HTTP, SMTP,...), files and file-like objects Inject mock code... as mock objects passed into production code functions or methods via an overwritten method in the production code class (this method may be a factory which returns a production code or a mock object) Keep your mock code simple. Avoid coding universal mock objects; they can become rather complicated and difficult to maintain Test your code under test, not its implementation Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.19/25

Testing at the right call level (1) Be careful when a mock object collects data at call levels which aren t directly executed by the code under test. In this case, your test code may become dependent on the implementation of the code under test, not only its interface. Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.20/25

Testing at the right call level (2) Example: Recursive save operations into an SQL database class X: def save(self): self.save_x_data() for y in self.ys: y.save() class Y: def save(self): self.save_y_data() for z in self.zs: z.save() class Z: def save(self): self.save_z_data() Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.21/25

Testing at the right call level (3) We want to test X s save method We use a mock database connection object which stores the corresponding SQL commands When examing the mock object after saving X, we find not only the commands to store the contained Y objects, but also commands for the Z objects: INSERT INTO x... INSERT INTO y... INSERT INTO z... INSERT INTO z... INSERT INTO y... INSERT INTO z... Thus, Y s implementation affects the test of X.save Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.22/25

When to use mock code How error-prone is the production code to test, or do we need the test to specify the interface? Do we need the test at all? Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.23/25

When to use mock code How error-prone is the production code to test, or do we need the test to specify the interface? Do we need the test at all? How difficult would a conventional test be (including any setup and cleanup for all tests and/or each test)? Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.23/25

When to use mock code How error-prone is the production code to test, or do we need the test to specify the interface? Do we need the test at all? How difficult would a conventional test be (including any setup and cleanup for all tests and/or each test)? Can we pass in a mock object and how complex does that mock object have to be? Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.23/25

When to use mock code How error-prone is the production code to test, or do we need the test to specify the interface? Do we need the test at all? How difficult would a conventional test be (including any setup and cleanup for all tests and/or each test)? Can we pass in a mock object and how complex does that mock object have to be? If we redesign the production code to use mock code, how difficult are the changes and how do they affect the maintainability of the changed production code? Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.23/25

Questions? Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.24/25

References Unit Test, http://www.c2.com/cgi/wiki?unittest Mock Object, http://www.c2.com/cgi/wiki?mockobject Endo-Testing: Unit Testing with Mock Objects, http://www.connextra.com/aboutus/ mockobjects.pdf Unit testing with mock code EuroPython 2004 Stefan Schwarzer p.25/25