KEMBAR78
Making Programs Fail | PDF | Model–View–Controller | Computing
0% found this document useful (0 votes)
11 views52 pages

Making Programs Fail

The document discusses the importance of testing in software development, emphasizing two main views: testing for validation and testing for debugging. It outlines various testing strategies, including automated tests, and highlights the significance of isolating failures and managing dependencies. Additionally, it introduces concepts such as the Model-View-Controller pattern and the principles of high cohesion and low coupling in software design.

Uploaded by

pnsocial acc
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
11 views52 pages

Making Programs Fail

The document discusses the importance of testing in software development, emphasizing two main views: testing for validation and testing for debugging. It outlines various testing strategies, including automated tests, and highlights the significance of isolating failures and managing dependencies. Additionally, it introduces concepts such as the Model-View-Controller pattern and the principles of high cohesion and low coupling in software design.

Uploaded by

pnsocial acc
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 52

Making Programs Fail

Andreas Zeller
Two Views of Testing

• Testing means to execute a program with


the intent to make it fail.

• Testing for validation:


Finding unknown failures (classical view)

• Testing for debugging:


Finding a specific failure (our focus)

2
Tests in Debugging

• Write a test to reproduce the problem


• Write a test to simplify the problem
• Run a test to observe the run
• Run a test to validate a fix
• Re-run tests to protect against regression
3
Automated Tests

• Allow for reuse of tests


• Allow tests that are difficult to carry out
manually

• Make tests repeatable


• Increase confidence in software

4
Automated Tests
• Allow to isolate and simplify
• failure-inducing input
• failure-inducing code changes
• failure-inducing thread schedules
• failure-inducing program state
• More on this in the weeks to come
5
Mozilla Bug #24735
Ok the following operations cause mozilla to crash
consistently on my machine

-> Start mozilla


-> Go to bugzilla.mozilla.org
How
-> Select search fordo
bugwe automate this?
-> Print to file setting the bottom and right margins to .50
(I use the file /var/tmp/netscape.ps)
-> Once it's done printing do the exact same thing again on
the same file (/var/tmp/netscape.ps)
-> This causes the browser to crash with a segfault

6
Simulating Interaction

Enter URL

Start Mozilla
Click on
Print
7
Challenges

• Synchronization: How do we know a


window has popped up such that we can
click into it?

• Abstraction: How do we know it’s the right


window?

• Portability: What happens on a display with


different resolution or window placement?

8
Interaction Layers

• The presentation layer handles interaction


with the user (generally: the environment)

• The functionality layer encapsulates the


functionality (independent from a specific
presentation)

• The unit layer splits functionality across


cooperating units

9
Control Layers

Presentation

Functionality

Units

10
Assessing Layers
• Ease of execution. How easy is it to get
control over program execution?

• Ease of interaction. How easy is it to


interact with the program?

• Ease of result assessment. How can we


check results against expectations?

• Lifetime of test case. How robust is my


test when it comes to program changes?
11
Presentation Layer

Presentation

Functionality

Units

12
Presentation Layer

• Low-level: expressing interaction by means


of mouse and keyboard events

• Also applicable at the system level


• High-level: expressing interaction using
graphical controls

13
Low Level Interaction
# 1. Launch mozilla and wait for 2 seconds
exec mozilla &
send_xevents wait 2000

# 2. Open URL dialog (Shift+Control+L)


send_xevents keydn Control_L
send_xevents keydn Shift_L
send_xevents key L
send_xevents keyup Shift_L
send_xevents keyup Control_L
send_xevents wait 500

# 3. Load bugzilla.mozilla.org and wait for 5 seconds


send_xevents @400,100
send_xevents type {http://bugzilla.mozilla.org}
send_xevents key Return
send_xevents wait 5000
14
Low Level Interaction

• Scripts can easily be recorded


• Scripts are write-only
(= impossible to maintain)

• Scripts are fragile


(= must be remade after trivial changes)

15
System Level Interaction

# Power on the machine and wait for 5s


power <= true; wait for 5000;

# Click mouse button 1


m_b1 <= true; wait for 300; m_b1 <= false;

# Click the CDROM change button


cdctrl'shortcut_out_add("/cdrom%change/...");

16
System Level Interaction

• Complete control over machine


• Good for testing and debugging system
properties

• Difficult to use for application programs

17
Higher Level Interaction
-- 1. Activate mozilla
tell application "mozilla" to activate

-- 2. Open URL dialog via menu


tell application "System Events" to ¬
tell process "mozilla" to ¬
tell menu bar 1 to ¬
tell menu bar item "File" to ¬
click menu item "Open Web Location"

-- 3. Load bugzilla.mozilla.org and wait for 5 seconds


tell window "Open Web Location"
tell sheet 1 to ¬
set value of text field 1 to "http://bugzilla.mozilla.org/"
click button 1
end tell
delay 5
18
Higher Level Interaction

• Scripts reference GUI elements by name


and numbers (rather than coordinates)

• Much more robust against size and position


changes

• But still fragile against layout changes and


renamings

19
Dealing with Output

• We must be able to detect output


• for synchronization (“is the dialog there?”)
• for assessment of results
(“was the test successful?”)

• Issue at entire presentation layer (low level,


system level, and high level interface)

20
Presentation Layer

• Automation is always feasible


• Scripts are more or less fragile
• Dealing with output is greatest weakness

21
Functionality Layer

Presentation

Functionality

Units

22
Design for Automation
• Each application comes with an API for a
scripting language
Check state
of application
tell application "Safari"
activate
if not (exists document 1)
make new document at the beginning of documents
end if
set the URL of the front document ¬
to "http://bugzilla.mozilla.org/"
delay 5
end tell

23
Windows Scripting
• Most operating systems provide their own
scripting language

' Load document


Set IE = CreateObject("InternetExplorer.Application")
IE.navigate "http://bugzilla.mozilla.org/"
IE.visible=1

' Wait until the page is loaded


While IE.Busy
WScript.Sleep 100
Wend

24
Emacs Scripting
• Some applications are built around a script
interpreter
(defun ispell-toggle ()
"Toggle ispell dictionary between english and german"
(interactive)
(cond ((equal ispell-local-dictionary nil)
(ispell-change-dictionary "american"))
((equal ispell-local-dictionary "deutsch8")
(ispell-change-dictionary "american"))
(t
(ispell-change-dictionary "deutsch8")))
(ispell-init-process)
(message (concat "Using " ispell-local-dictionary
"ispell dictionary")))
25
Scripting Languages
• OS-specific languages (MacOS, Windows)
• Perl, Python, Tcl
• Lisp, Scheme, Guile
• Command-line languages (Unix shell)
• Component languages (.NET, Corba)
• … or roll your own (but beware!)
26
Functionality Layer

• Results can be easily assessed


• Scripts are robust against changes (as long
as automation interface remains stable)

• Requires clear separation between


presentation and functionality

27
Unit Layer

Presentation

Functionality

Units

28
Unit Tests

• Directly access units (= classes, modules,


components…) at their programming
interfaces

• Encapsulate a set of tests as a single


syntactical unit

• Available for all programming languages


(JUNIT for Java, CPPUNIT for C++, etc.)

29
Running a Test

A test case…
1. sets up an environment for the test
2. tests the unit
3. tears down the environment again.

30
Testing a URL Class

http://www.askigor.org/status.php?id=sample

Protocol Host Path Query

31
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;

public class URLTest extends TestCase {


private URL askigor_url;

// Create new test


public URLTest(String name) { super(name); }

// Assign a name to this test case


public String toString() { return getName(); }

// Setup environment
protected void setUp() {
askigor_url = new URL("http://www.askigor.org/" +
"status.php?id=sample"); }
// Release environment
protected void tearDown() { askigor_url = null;}

32
// Test for protocol (http, ftp, etc.)
public void testProtocol() {
assertEquals(askigor_url.getProtocol(), "http");
}
The test case
// Test for host can be used
public void testHost() { as a specification!
int noPort = -1;
assertEquals(askigor_url.getHost(), "www.askigor.org");
assertEquals(askigor_url.getPort(), noPort);
}

// Test for path


public void testPath() {
assertEquals(askigor_url.getPath(), "/status.php");
}

// Test for query part


public void testQuery() {
assertEquals(askigor_url.getQuery(), "id=sample");
}
33
// Set up a suite of tests
public static Test suite() {
TestSuite suite = new TestSuite(URLTest.class);
return suite;
}

// Main method: Invokes GUI


public static void main(String args[]) {
String[] testCaseName =
{ URLTest.class.getName() };
// junit.textui.TestRunner.main(testCaseName);
junit.swingui.TestRunner.main(testCaseName);
// junit.awtui.TestRunner.main(testCaseName);
}
}

34
JUnit

35
PyUnit

• Unit testing framework for Python


• Simple variant: just overload runTest()
import unittest

class DefaultWidgetSizeTestCase(unittest.TestCase):
def runTest(self):
widget = Widget("The widget")
assert widget.size() == (50,50), \
'incorrect default size'

36
PyUnit Fixtures
class WidgetTestCase(unittest.TestCase):
def setUp(self):
self.widget = Widget("The widget")
def tearDown(self):
self.widget.dispose()
self.widget = None
def testDefaultSize(self):
assert self.widget.size() == (50,50), \
'incorrect default size'
def testResize(self):
self.widget.resize(100,150)
assert self.widget.size() == (100,150), \
'wrong size after resize'
37
Running PyUnit tests

if __name__ == “__main__”:
unittest.main()

$ python unittest.py widgettests.WidgetTestSuite

http://pyunit.sourceforge.net/pyunit.html
38
Isolating Units
• How do we deal with classes that depend
on others?
void print_to_file(string filename)
{
if (path_exists(filename)) {
// FILENAME exists; ask user to confirm overwrite
bool confirmed = confirm_loss(filename);
if (!confirmed)
return;
}
// Proceed printing to FILENAME...
}

39
Circular Dependency

invokes

Core UserPresentation
+print_to_file() +confirm_loss()

invokes

Both units depend on each other!

40
Broken Dependency
void print_to_file(string filename,
Presentation *presentation)
{
if (path_exists(filename))
{
// FILENAME exists;
// ask user to confirm overwrite
bool confirmed =
presentation->confirm_loss(filename);
if (!confirmed)
return;
}

// Proceed printing to FILENAME


...
}
41
Revised Dependency
Core Presentation
+print_to_file() +confirm_loss()

UserPresentation AutomatedPresentation
+confirm_loss() +confirm_loss()

ask user return true;

Depend on abstraction rather than details!


42
Dependency Inversion

To break the dependency from A to B,


1. Introduce an abstract superclass B’
2. Set up A such that it depends on B’
(rather than B)
3. Introduce alternate subclasses of B’ that
can be used with A

43
Design for Debugging

• Basic idea: decompose the system such that


dependencies are minimized

• Each component depends on a minimum of


other components for testing (and
debugging)

44
Model-View-Controller
Black: 48%
Red:
Green:
28%
10%
Separate functionality
Yellow:
Pink:
6%
4%
and presentations
Others: 4%

Black 48
Red 28
Green 10
Yellow 6
Pink 4
Others 4 User

45
The MVC Pattern
Model
-coreData Register observers
+attach(Observer)
+detach(Observer)
+notify()
+getData()
+service() Notify observers
1

observers

0..*
Observer update view
+update()

View
Controller
+initialize(Model) 1 0..1
+makeController() +initialize(Model,View)
+activate() +handleEvent()
+display() +update()
+update()
46
General Design Rules

• High cohesion. Those units that operate on


common data should be grouped together.

• Low coupling. Units that do not share


common data should exchange as little
information as possible.

47
Prevent Problems

Specify Test early Test first

Have
Test often Test enough
reviews
Check the
Verify Assert
code

48
Concepts
To test for debugging, one must…

• create a test to reproduce the problem


• run the test several times during
debugging, and

• run the test before new releases to


prevent regression
Automate as much as possible

49
Concepts (2)

To test at the presentation layer, simulate


human interaction
To test at the functionality layer, use an
automation interface
To test units, use the unit API to control it
and assess its results

50
Concepts (3)

To isolate a unit, break dependencies using


the dependency inversion principle
To design for debugging, reduce the amount
of dependencies
A variety of techniques is available to
prevent errors and problems

51
52

You might also like