You are here:

Spy is a flexible and open framework for designing and implementing program monitor. Spy enables easy-to-realize analysis.

Spy has been instantiated into three tools, Kai, Hapa’o and Keri.


The source code may be browsed online and downloaded from http://www.squeaksource.com/Spy.html. To install Spy, just evaluate the following in a Workspace:

Gofer new
squeaksource: 'Spy';
package: 'ConfigurationOfSpy';
(Smalltalk at: #ConfigurationOfSpy) project lastVersion load

Simple Example

Spy enables one to easily write a code profiler. When coupled with Mondrian, profiled information may be easily graphically rendered.

For example, a very primitive test coverage tool could be defined as:

MethodSpy subclass: #DemoTestCoverageMethodSpy
instanceVariableNames: 'nbOfExecutions testMethodsThatRunMe'
classVariableNames: ''
poolDictionaries: ''
category: 'Spy-DemoTestCoverage'

super initialize.
nbOfExecutions := 0.
testMethodsThatRunMe := Set new.

DemoTestCoverageMethodSpy>>beforeRun: methodName with: listOfArguments in: receiver
nbOfExecutions := nbOfExecutions + 1.
testMethodsThatRunMe add: self profiler class currentTestMethod

^ nbOfExecutions

^ testMethodsThatRunMe

The code above create a subclass of MethodSpy, a kind of wrapper for methods. Each time a method on which this wrapper is installed will invoke the method beforeRun:with:in: before. Other hooks are available in MethodSpy.

You then need to create a spy for classes and packages:

ClassSpy subclass: #DemoTestCoverageClassSpy
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'Spy-DemoTestCoverage'

"The following methods are defined on the class side!"
DemoTestCoverageClassSpy class>>spyClassForMethod
^ DemoTestCoverageMethodSpy

PackageSpy subclass: #DemoTestCoveragePackageSpy
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'Spy-DemoTestCoverage'

DemoTestCoveragePackageSpy class>>spyClassForClass
^ DemoTestCoverageClassSpy

You then need to subclass the class Profiler:

Profiler subclass: #DemoTestCoverage
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'Spy-DemoTestCoverage'

"Defined on the class side!"
DemoTestCoverage class>>spyClassForPackage
^ DemoTestCoveragePackageSpy

You can simply invoke it with:

| profiler |
profiler := DemoTestCoverage runTestsForPackagesMatching: 'Roassal*'.

You can then perform simple queries such as:

(profiler allMethods select: [ :m | m nbOfExecutions = 0]) size
=> 650

The code above says that 650 methods in Roassal are not executed when running Mondrian tests. The total amount of methods is

profiler allMethods size
=> 2368

(profiler allMethods asSortedCollection: 
[:m1 :m2 | m1 testMethodsThatRunMe size > m2 testMethodsThatRunMe size ]) copyFrom: 1 to: 3
=> a SortedCollection(<ROObject>>initialize> <RONullShape>>extent:> <RONullShape>>initialize>)

The result is the three methods that are the most executed by different test methods.

Visualizing the Profiling

The profiling information obtained above become significant when being visualized. The Roassal agile visualization engine is used for this.

A visualization can be implemented by overriding #visualizeOn: in the package spy class:

DemoTestCoveragePackageSpy>>visualizeOn: view
view nodes: self allClasses forEach: [:each |
view shape rectangle
size: 15;
linearFillColor: [ :m | ((m nbOfExecutions + 1) log * 10) asInteger ] within: self allMethods.
view nodes: (each methods sortedAs: #nbOfExecutions).
view gridLayout gapSize: 2.
view edgesFrom: #superclass.
view treeLayout

The visualization is obtained by executing:

profiler visualize

The visualization obtained is exemplified:

Large squares are classes. Edges represent superclass links (above is a superclass of below). Inner classes are methods. The color tells about its number of execution: white methods are the one not covered by the unit tests, and the dark one are the methods executed many times.


Information about the principal author of Spy may be found on http://www.bergel.eu

Kai, Hapa’o, Keri

South America, and especially Chile, has a strong link with Polynesia. Kai, Hapa’o and Keri are three words in Rapanui, the native language (still) spoken in Easter Island.

License: MIT