Automatisierte Akzeptanztests und
TDD für iOS
Sven Günther - it-agile GmbH
Donnerstag, 6. Dezember 12
User Storys
Als <Rolle> möchte ich <Funktionalität> damit
<Geschäftswert>
Donnerstag, 6. Dezember 12
Woher kommen die Details?
User Story
Donnerstag, 6. Dezember 12
Woher kommen die Details?
User Story
User Story
Donnerstag, 6. Dezember 12
Woher kommen die Details?
User Story
User Story User Story
Donnerstag, 6. Dezember 12
Woher kommen die Details?
User Story
User Story User Story User Story
Donnerstag, 6. Dezember 12
Woher kommen die Details?
User Story
User Story User Story User Story
Story-Splitting
Donnerstag, 6. Dezember 12
Woher kommen die Details?
User Story
Donnerstag, 6. Dezember 12
Woher kommen die Details?
User Story
Example 1
Donnerstag, 6. Dezember 12
Woher kommen die Details?
User Story
Example 1
Example II
Donnerstag, 6. Dezember 12
Woher kommen die Details?
User Story
Example 1
Example II
Example III
Donnerstag, 6. Dezember 12
Woher kommen die Details?
User Story
Example 1
Example II
Example III
Examples
Donnerstag, 6. Dezember 12
Anatomie einer ausführbaren Spezifikationen
Donnerstag, 6. Dezember 12
Anatomie einer ausführbaren Spezifikationen
Ausführbares Beispiel
Donnerstag, 6. Dezember 12
Anatomie einer ausführbaren Spezifikationen
Ausführbares Beispiel beschreibt die Anforderungen
Donnerstag, 6. Dezember 12
Anatomie einer ausführbaren Spezifikationen
Ausführbares Beispiel
ausführbare Schritte
beschreibt die Anforderungen
Donnerstag, 6. Dezember 12
Anatomie einer ausführbaren Spezifikationen
Ausführbares Beispiel
ausführbare Schritte
beschreibt die Anforderungen
bildet Vokabular ab
Donnerstag, 6. Dezember 12
Anatomie einer ausführbaren Spezifikationen
Ausführbares Beispiel
ausführbare Schritte
Treiber
beschreibt die Anforderungen
bildet Vokabular ab
Donnerstag, 6. Dezember 12
Anatomie einer ausführbaren Spezifikationen
Ausführbares Beispiel
ausführbare Schritte
Treiber
beschreibt die Anforderungen
bildet Vokabular ab
steuert die zu testende Anwendung
Donnerstag, 6. Dezember 12
Anatomie einer ausführbaren Spezifikationen
Ausführbares Beispiel
ausführbare Schritte
Treiber
Anwendung
beschreibt die Anforderungen
bildet Vokabular ab
steuert die zu testende Anwendung
Donnerstag, 6. Dezember 12
Anatomie einer ausführbaren Spezifikationen
Ausführbares Beispiel
ausführbare Schritte
Treiber
Anwendung
beschreibt die Anforderungen
bildet Vokabular ab
steuert die zu testende Anwendung
getestetes System
Donnerstag, 6. Dezember 12
Cucumber
Donnerstag, 6. Dezember 12
Cucumberhttp://cukes.info
works with Ruby, Java, .NET, Flex or web applications written in any language
Donnerstag, 6. Dezember 12
Cucumberhttp://cukes.info
works with Ruby, Java, .NET, Flex or web applications written in any language
gem install cucumber
Donnerstag, 6. Dezember 12
Given - When - Then
Given <Vorbedingung>
When <Handlung, Aktion>
Then <beobachtbares Ergebnis>
Donnerstag, 6. Dezember 12
Given - When - Then
Given the browser shows the google homepage
When I enter "iPhone" into the the search field
Then I should see search results regarding "iPhone"
Donnerstag, 6. Dezember 12
Feature: AdditionIn order to avoid silly mistakesAs a math idiotI want to be told the sum of two numbers
Scenario: Add two numbersGiven I have entered 50 into the calculatorAnd I have entered 70 into the calculatorWhen I press addThen the result should be 120 on the screen
Feature-File
Donnerstag, 6. Dezember 12
Step-Definition
Given /I have entered (.*) into the calculator/ do |n|calculator = Calculator.newcalculator.push(n.to_i)
end
Donnerstag, 6. Dezember 12
Frank
Donnerstag, 6. Dezember 12
Frankwww.testingwithfrank.com
Donnerstag, 6. Dezember 12
Frankwww.testingwithfrank.com
Initiiert von Pete Hodgson (Thoughtworks)
Donnerstag, 6. Dezember 12
Frankwww.testingwithfrank.com
Initiiert von Pete Hodgson (Thoughtworks)
iOS-Treiber für cucumber
Donnerstag, 6. Dezember 12
Frankwww.testingwithfrank.com
Initiiert von Pete Hodgson (Thoughtworks)
iOS-Treiber für cucumber
Donnerstag, 6. Dezember 12
Demo
Donnerstag, 6. Dezember 12
TDD
Donnerstag, 6. Dezember 12
Warum TDD?
Donnerstag, 6. Dezember 12
Warum TDD?
Besseres Design weil
Donnerstag, 6. Dezember 12
Warum TDD?
Besseres Design weil
• voneinander losgelöste Einheiten entstehen
Donnerstag, 6. Dezember 12
Warum TDD?
Besseres Design weil
• voneinander losgelöste Einheiten entstehen
• die früh in der Entwicklung benutzt werden (durch die Tests)
Donnerstag, 6. Dezember 12
Warum TDD?
Besseres Design weil
• voneinander losgelöste Einheiten entstehen
• die früh in der Entwicklung benutzt werden (durch die Tests)
Sicherheitsnetz durch durchgängige Testsuite
Donnerstag, 6. Dezember 12
Wie ???
Donnerstag, 6. Dezember 12
Wie ???
Test
neue Funktionalität wird durch Test beschrieben
Donnerstag, 6. Dezember 12
Wie ???
Test
neue Funktionalität wird durch Test beschrieben
GreenFunktionalität wird
implementiert
Donnerstag, 6. Dezember 12
Wie ???
Test
neue Funktionalität wird durch Test beschrieben
GreenFunktionalität wird
implementiertRefactorCode wird aufgeräumt
Donnerstag, 6. Dezember 12
Wie ???
Test
neue Funktionalität wird durch Test beschrieben
GreenFunktionalität wird
implementiertRefactorCode wird aufgeräumt
Donnerstag, 6. Dezember 12
OCUnit - Anatomie eines Tests
Donnerstag, 6. Dezember 12
OCUnit - Anatomie eines Tests
#import <SenTestingKit/SenTestingKit.h>
Donnerstag, 6. Dezember 12
OCUnit - Anatomie eines Tests
#import <SenTestingKit/SenTestingKit.h>
@interface SmokeTest : SenTestCase@end
Donnerstag, 6. Dezember 12
OCUnit - Anatomie eines Tests
#import <SenTestingKit/SenTestingKit.h>
@interface SmokeTest : SenTestCase@end
@implementation SmokeTest
Donnerstag, 6. Dezember 12
OCUnit - Anatomie eines Tests
#import <SenTestingKit/SenTestingKit.h>
@interface SmokeTest : SenTestCase@end
@implementation SmokeTest
- (void)testThatItHaveSmoked {! STAssertEqualObjects(@"foo", @"bar", @"Description");}
Donnerstag, 6. Dezember 12
OCUnit - Anatomie eines Tests
#import <SenTestingKit/SenTestingKit.h>
@interface SmokeTest : SenTestCase@end
@implementation SmokeTest
- (void)testThatItHaveSmoked {! STAssertEqualObjects(@"foo", @"bar", @"Description");}
@end
Donnerstag, 6. Dezember 12
setup / tearDown
Donnerstag, 6. Dezember 12
setup / tearDown
@implementation SmokeTest
Donnerstag, 6. Dezember 12
setup / tearDown
@implementation SmokeTest
- (void)setUp {! // initialisiere Testumgebung}
Donnerstag, 6. Dezember 12
setup / tearDown
@implementation SmokeTest
- (void)setUp {! // initialisiere Testumgebung}
- (void)tearDown {! // räume Testumgebung wieder ab}
Donnerstag, 6. Dezember 12
setup / tearDown
@implementation SmokeTest
- (void)setUp {! // initialisiere Testumgebung}
- (void)tearDown {! // räume Testumgebung wieder ab}
Donnerstag, 6. Dezember 12
setup / tearDown
@implementation SmokeTest
- (void)setUp {! // initialisiere Testumgebung}
- (void)tearDown {! // räume Testumgebung wieder ab}
- (void)test... {}
Donnerstag, 6. Dezember 12
setup / tearDown
@implementation SmokeTest
- (void)setUp {! // initialisiere Testumgebung}
- (void)tearDown {! // räume Testumgebung wieder ab}
- (void)test... {}
@end
Donnerstag, 6. Dezember 12
MeinObjektTest
testMachtDies
testMachtDas
testMachtJenes
Tests als Dokumentation
Donnerstag, 6. Dezember 12
MeinObjekt
MachtDies
MachtDas
MachtJenes
Tests als Dokumentation
Donnerstag, 6. Dezember 12
Assertions prüfen
Donnerstag, 6. Dezember 12
STAssertEqualObjects(@"foo", @"bar", @"foo should be bar");
STAssertEquals(6*7, 45, @"6 x 7 should be 42");
STAssertNil(nil, @"nil should be nil");
Assertions prüfen
Donnerstag, 6. Dezember 12
STAssertEqualObjects(@"foo", @"bar", @"foo should be bar");
STAssertEquals(6*7, 45, @"6 x 7 should be 42");
STAssertNil(nil, @"nil should be nil");
NSArray *array = @[foo, bar];STAssertTrue([array indexOfObject:foo] > 0, @"array should contain foo");
STAssertEqualObjects(@"foo", @"bar", @"foo should be bar");
STAssertEquals(6*7, 45, @"6 x 7 should be 42");
STAssertNil(nil, @"nil should be nil");
Assertions prüfen
Donnerstag, 6. Dezember 12
STAssertEqualObjects(@"foo", @"bar", @"foo should be bar");
STAssertEquals(6*7, 45, @"6 x 7 should be 42");
STAssertNil(nil, @"nil should be nil");
NSArray *array = @[foo, bar];STAssertTrue([array indexOfObject:foo] > 0, @"array should contain foo");
STAssertEqualObjects(@"foo", @"bar", @"foo should be bar");
STAssertEquals(6*7, 45, @"6 x 7 should be 42");
STAssertNil(nil, @"nil should be nil");
Assertions prüfenSTAssertEqualObjects(@"foo", @"bar", @"foo should be bar");
STAssertEquals(6*7, 45, @"6 x 7 should be 42");
STAssertNil(nil, @"nil should be nil");
NSArray *array = @[foo, bar];STAssertTrue([array indexOfObject:foo] > 0, @"array should contain foo");
"[array indexOfObject:foo] > 0" should be true. array should contain foo
Donnerstag, 6. Dezember 12
Expecta
Donnerstag, 6. Dezember 12
github.com/petejkim/expecta
Expecta
Donnerstag, 6. Dezember 12
github.com/petejkim/expecta
expect(foo).to.equal(@"foo");expect(bar).notTo.equal(@"foo");
github.com/petejkim/expecta
Expecta
Donnerstag, 6. Dezember 12
github.com/petejkim/expecta
expect(foo).to.equal(@"foo");expect(bar).notTo.equal(@"foo");
NSArray *array = @[bar, foobar];expect(array).to.contain(foo);
github.com/petejkim/expecta
expect(foo).to.equal(@"foo");expect(bar).notTo.equal(@"foo");
github.com/petejkim/expecta
Expecta
Donnerstag, 6. Dezember 12
github.com/petejkim/expecta
expect(foo).to.equal(@"foo");expect(bar).notTo.equal(@"foo");
NSArray *array = @[bar, foobar];expect(array).to.contain(foo);
github.com/petejkim/expecta
expect(foo).to.equal(@"foo");expect(bar).notTo.equal(@"foo");
github.com/petejkim/expectagithub.com/petejkim/expecta
expect(foo).to.equal(@"foo");expect(bar).notTo.equal(@"foo");
NSArray *array = @[bar, foobar];expect(array).to.contain(foo);
expected (bar, foobar) to contain foo
Expecta
Donnerstag, 6. Dezember 12
Expecta
Donnerstag, 6. Dezember 12
expect(x).to.haveCountOf(y);
Expecta
Donnerstag, 6. Dezember 12
expect(x).to.haveCountOf(y);
expect(x).to.beEmpty();
Expecta
Donnerstag, 6. Dezember 12
expect(x).to.haveCountOf(y);
expect(x).to.beEmpty();
expect(x).to.beLessThan(y);
Expecta
Donnerstag, 6. Dezember 12
expect(x).to.haveCountOf(y);
expect(x).to.beEmpty();
expect(x).to.beLessThan(y);
expect(x).to.beGreaterThan(y);
Expecta
Donnerstag, 6. Dezember 12
expect(x).to.haveCountOf(y);
expect(x).to.beEmpty();
expect(x).to.beLessThan(y);
expect(x).to.beGreaterThan(y);
expect(x).to.beCloseToWithin(y, z);
Expecta
Donnerstag, 6. Dezember 12
Expecta
Donnerstag, 6. Dezember 12
expect(x).will.beNil();
Expecta
Donnerstag, 6. Dezember 12
expect(x).will.beNil();
[Expecta setAsynchronousTestTimeout:x]
Expecta
Donnerstag, 6. Dezember 12
Expecta
Donnerstag, 6. Dezember 12
@interface LightSwitch : NSObject
Expecta
Donnerstag, 6. Dezember 12
@interface LightSwitch : NSObject
@property (nonatomic, assign, getter=isTurnedOn) BOOL turnedOn;
Expecta
Donnerstag, 6. Dezember 12
@interface LightSwitch : NSObject
@property (nonatomic, assign, getter=isTurnedOn) BOOL turnedOn;
@end
Expecta
Donnerstag, 6. Dezember 12
@interface LightSwitch : NSObject
@property (nonatomic, assign, getter=isTurnedOn) BOOL turnedOn;
@end
expect(lightSwitch).isTurnedOn();
Expecta
Donnerstag, 6. Dezember 12
Demo
Donnerstag, 6. Dezember 12
Test-Stellvertreter
• dienen als Stellvertreter für reale Objekte
Donnerstag, 6. Dezember 12
Test-Stellvertreter
• dienen als Stellvertreter für reale Objekte
• sind essentiell zum Entkoppeln von Abhängigkeiten
Donnerstag, 6. Dezember 12
Test-Stellvertreter
• dienen als Stellvertreter für reale Objekte
• sind essentiell zum Entkoppeln von Abhängigkeiten
• Simulieren Interaktionen mit anderen Objekten
Donnerstag, 6. Dezember 12
Test-Stellvertreter
• dienen als Stellvertreter für reale Objekte
• sind essentiell zum Entkoppeln von Abhängigkeiten
• Simulieren Interaktionen mit anderen Objekten
- Mocks = Stellvertreter die ein erwartetes Verhalten überprüfen
Donnerstag, 6. Dezember 12
Test-Stellvertreter
• dienen als Stellvertreter für reale Objekte
• sind essentiell zum Entkoppeln von Abhängigkeiten
• Simulieren Interaktionen mit anderen Objekten
- Mocks = Stellvertreter die ein erwartetes Verhalten überprüfen
- Stubs = Stellvertreter mit einem definierten Ein- / Ausgabeverhalten
Donnerstag, 6. Dezember 12
Abhängigkeiten abschneiden
MyClass
Donnerstag, 6. Dezember 12
Abhängigkeiten abschneiden
MyClass OtherClassuses
Donnerstag, 6. Dezember 12
Abhängigkeiten abschneiden
MyClass
MyTest
OtherClassuses
tests
Donnerstag, 6. Dezember 12
Abhängigkeiten abschneiden
MyClass
MyTest
OtherClass
a Mock
uses
tests pretends to be
Donnerstag, 6. Dezember 12
Abhängigkeiten abschneiden
MyClass
MyTest
OtherClass
a Mock
uses
tests pretends to be
uses
✗
Donnerstag, 6. Dezember 12
Dependency Injection
Donnerstag, 6. Dezember 12
Dependency Injection
• Klassen erzeugen von selbst keine neuen Abhängigkeiten
Donnerstag, 6. Dezember 12
Dependency Injection
• Klassen erzeugen von selbst keine neuen Abhängigkeiten
- z.B. kein [[... alloc] init]
Donnerstag, 6. Dezember 12
Dependency Injection
• Klassen erzeugen von selbst keine neuen Abhängigkeiten
- z.B. kein [[... alloc] init]
• Abhängigkeiten werden von außen hereingereicht
Donnerstag, 6. Dezember 12
Dependency Injection
• Klassen erzeugen von selbst keine neuen Abhängigkeiten
- z.B. kein [[... alloc] init]
• Abhängigkeiten werden von außen hereingereicht
- setter (@property)
Donnerstag, 6. Dezember 12
Dependency Injection
• Klassen erzeugen von selbst keine neuen Abhängigkeiten
- z.B. kein [[... alloc] init]
• Abhängigkeiten werden von außen hereingereicht
- setter (@property)
- Konstruktor (initWith...)
Donnerstag, 6. Dezember 12
OCMockito
Donnerstag, 6. Dezember 12
OCMockitogithub.com/jonreid/OCMockito
Donnerstag, 6. Dezember 12
OCMockitogithub.com/jonreid/OCMockito
#define HC_SHORTHAND#import <OCHamcrestIOS/OCHamcrestIOS.h>
Donnerstag, 6. Dezember 12
OCMockitogithub.com/jonreid/OCMockito
#define HC_SHORTHAND#import <OCHamcrestIOS/OCHamcrestIOS.h>
#define MOCKITO_SHORTHAND#import <OCMockitoIOS/OCMockitoIOS.h>
Donnerstag, 6. Dezember 12
Beispiel Mocks
Donnerstag, 6. Dezember 12
Beispiel Mocks
NSMutableArray *mockArray = mock([NSMutableArray class]);
Donnerstag, 6. Dezember 12
Beispiel Mocks
NSMutableArray *mockArray = mock([NSMutableArray class]);
[mockArray addObject:@"one"];[mockArray removeAllObjects];
Donnerstag, 6. Dezember 12
Beispiel Mocks
NSMutableArray *mockArray = mock([NSMutableArray class]);
[mockArray addObject:@"one"];[mockArray removeAllObjects];
[verify(mockArray) addObject:@"one"];[verify(mockArray) removeAllObjects];
Donnerstag, 6. Dezember 12
Beispiel Stub
Donnerstag, 6. Dezember 12
Beispiel Stub
NSArray *mockArray = mock([NSArray class]);
Donnerstag, 6. Dezember 12
Beispiel Stub
NSArray *mockArray = mock([NSArray class]);
[given([mockArray objectAtIndex:0]) willReturn:@"first"];
Donnerstag, 6. Dezember 12
Beispiel Stub
NSArray *mockArray = mock([NSArray class]);
[given([mockArray objectAtIndex:0]) willReturn:@"first"];
NSLog(@"%@", [mockArray objectAtIndex:0]);
Donnerstag, 6. Dezember 12
Demo
Donnerstag, 6. Dezember 12
Fragen?
Donnerstag, 6. Dezember 12
Fragen?
http://www.it-agile.de/mobile.html
Donnerstag, 6. Dezember 12