Automated UI testing should be an essential part of your application as it gets bigger. While browser applications rely on the popular Selenium WebDriver it was not possible to efficiently test Morphic user interfaces - until now.
-
Load Metacello
-
Load the testing framework with the following command:
Metacello new baseline: 'MorphicTestingFramework'; repository: 'github://hpi-swa-teaching/Morphic-Testing-Framework:master/packages'; load.
You can write your UI tests just as your unit tests and run them in the SUnit test runner. To create a UI test case, simply inherit it from MTFTestCase and you get all the SUnit stuff plus the frameworks UI testing abilities:
MTFTestCase subclass: #MyUITestCase
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'MyCategory'
To test your interface, overwrite the setUp message:
MyUITestCase>>setUp
self wantsToTest: MyUserInterface new.
Now we could test that our button named 'fancy' changes its color when it is clicked:
MyUITestCase>>testFancyClick
|button|
button := self subject findByClass: SimpleButtonMorph.
self assert: button color = Color white.
button click.
self assert: button color = Color red.
For more detailed examples of how to use the framework, refer to the API section or take a look at the MTFCalculatorTests in the Morphic-Testing-Framework-Tests package.
MTFTestCase>>wantsToTest: aMorph
should be called in your MTFTestCase>>setUp
.
It sets the subject of the test case to be accessible as an MTFMorphWrapper in your test methods.
Example:
MTFTestCase>>setUp
self wantsToTest: MyUserInterface new.
Returns the morph wrapper for the morph specified in MTFTestCase>>wantsToTest: aMorph
.
By default all tests run headless meaning you cannot trace the performed interactiosn visually. To change this, this message allows you to delay all interactions by the given number of milliseconds. You can call MTFTestCase>>slowTestBy:
to run the test visually. In this case the subject is shown in the world and the interactions are slowed down. Therefore, you can follow the test. Note: You should not call openInWorld on the morph you want to test by yourself.
- MTFMorphWrapper>>leftMouseClickWith
- MTFMorphWrapper>>leftMouseClickWith: modifiers
- MTFMorphWrapper>>rightMouseClickWith
- MTFMorphWrapper>>rightMouseClickWith: modifiers
- MTFMorphWrapper>>middleMouseClickWith
- MTFMorphWrapper>>middleMouseClickWith: modifiers
Sends a left/right/middle click event to all morphs contained in the wrapper. The modifiers
argument is used to simulate clicks combined with pressed SHIFT, CTRL or CMD and can be omitted. If you want to use modifiers use the conctant defined in the MTFMorphWrapper as in the following example:
MyTestCase>>testThis
self subject leftMouseClickWith: MTFMorphWrapper shiftModifier.
self subject rightMouseClick.
- MTFMorphWrapper>> leftMouseDownWith
- MTFMorphWrapper>> leftMouseDownWith: modifiers
- MTFMorphWrapper>> rightMouseDownWith
- MTFMorphWrapper>> rightMouseDownWith: modifiers
- MTFMorphWrapper>> middleMouseDownWith
- MTFMorphWrapper>> middleMouseDownWith: modifiers
Sends a left/right/middle mouse down event to all morphs contained in the wrapper. The modifiers
argument is used to simulate mouse down events combined with pressed SHIFT, CTRL or CMD and can be omitted. If you want to use modifiers use the conctant defined in the MTFMorphWrapper as in the following example:
MyTestCase>>testThis
self subject leftMouseDownWith: MTFMorphWrapper shiftModifier.
self subject rightMouseDown.
- MTFMorphWrapper>> leftMouseUpWith
- MTFMorphWrapper>> leftMouseUpWith: modifiers
- MTFMorphWrapper>> rightMouseUpWith
- MTFMorphWrapper>> rightMouseUpWith: modifiers
- MTFMorphWrapper>> middleMouseUpWith
- MTFMorphWrapper>> middleMouseUpWith: modifiers
Sends a left/right/middle mouse up event to all morphs contained in the wrapper. The modifiers
argument is used to simulate mouse downup events combined with pressed SHIFT, CTRL or CMD and can be omitted. If you want to use modifiers use the conctant defined in the MTFMorphWrapper as in the following example:
MyTestCase>>testThis
self subject leftMouseUpWith: MTFMorphWrapper shiftModifier.
self subject rightMouseUp.
Sends a keystroke event for the specified character to all morphs contained in the wrapper.
Sends a the specified string to all morphs contained in the wrapper.
Internally, sendKey
is used, so
MyTestCase>>testThis
self subject sendKey: 'H'.
self subject sendKey: 'e'.
self subject sendKey: 'l'.
self subject sendKey: 'l'.
self subject sendKey: 'o'.
is equivalent to
MyTestCase>>testThis
self subject sendKeys: 'Hello'.
This is the generic method you can use to create custom key. Here is an example how this is used to implement MTFMorphWrapper>>sendKey:
.
MTFMorphWrapper>>sendKey: aCharacter
self sendKeyEvent: #keystroke characterValue: aCharacter asInteger.
Recursively finds all submorphs that have the passed name and returns a wrapper containing them.
Note: Giving mutliple morphs the same name is generally a bad practice.
Recursively finds all submorphs that are instances of the passed class and returns a wrapper containing them.
Recursively finds all submorphs that have the passed label and returns a wrapper containing them.
Note: This refers to the label message available for example on a SimpleButtonMorph. This only works on the Morph classes explicitly defined in the framework. can