Skip to content

hpi-swa-teaching/Morphic-Testing-Framework

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Morphic Testing Framework Build Status

Morphic Testing Framework

Introduction

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.

Getting started

Installation

  1. Load Metacello

  2. Load the testing framework with the following command:

    Metacello new
    	baseline: 'MorphicTestingFramework';
    	repository: 'github://hpi-swa-teaching/Morphic-Testing-Framework:master/packages';
    	load.

First test

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.

Give me more

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.

API

Setup

MTFTestCase>>wantsToTest: aMorph

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.
MTFTestCase>>subject

Returns the morph wrapper for the morph specified in MTFTestCase>>wantsToTest: aMorph.

MTFTestCase>>slowTestBy: aNumber

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.

Simulate interactions

Mouse Clicks

  • 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.

Mouse Down

  • 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.

Mouse Up

  • 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.

Key Events

MTFMorphWrapper>>sendKey: aCharacter

Sends a keystroke event for the specified character to all morphs contained in the wrapper.

MTFMorphWrapper>>sendKeys: aString

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'.
MTFMorphWrapper>>sendKeyEvent: aType characterValue: aValue

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.

Find morphs

MTFMorphWrapper>>findByName: aString

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.

MTFMorphWrapper>>findByClass: aClass

Recursively finds all submorphs that are instances of the passed class and returns a wrapper containing them.

MTFMorphWrapper>>findByLabel: aString

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