2013-11-15 1 views
18

Ich habe gerade mit dem E2E-Test für Winkelmesser begonnen, und ich habe ein paar Probleme mit der Testfallstruktur.Kann ich meine Tests in separate Spezifikationen aufteilen und sie dann von einer anderen aufrufen oder ist es besser, Hilfsfunktionen zu verwenden?

Nicht sicher, ob ich meine Tests in separate Spezifikationen aufteilen und sie dann von einem anderen aufrufen kann oder wie kann ich nette Hilfsfunktionen machen, um damit umzugehen.

Ich finde Elemente von einem Repeater und dann möchte ich Tests für jede Operation für jedes Element im Repeater machen. Art wie folgt aus:

describe('tasty', function() { 
    'use strict'; 
    var ptor; 

    beforeEach(function() { 
     ptor = protractor.getInstance(); 
     ptor.get('http://localhost:8000/'); 
    }); 

    it('Should sample three tasty fruits of every kind on my shopping list.', function() { 
     ptor.findElement(protractor.By.className('fruitstore')).click(); 
     var fruitshelves = ptor.findElements(protractor.By.repeater('fruit in fruits').column('header')); 

     fruitshelves.then(function(arr) { 
      for (var i=0;i<arr.length; i++) { 
       // Pick up three fruits of this kind from the shelf and put in shopping cart 
       // Should be listed on my shopping list 
       // Open the wallet 
       // Should have money 
       // Pay for the fruits and put it in your shopping bag 
       // Should be able to complete the transaction 

       // For each one of the fruits in your shopping bag 
       // Take a bite 
       // Should be tasty 
      } 
     }); 
    }); 
}); 

Antwort

10

Ich kam zu dieser Frage auf der Suche nach einer Möglichkeit, Hilfsfunktionen zwischen Spec-Dateien in Winkelmesser zu teilen. Für den Fall, dass andere nach dem gleichen suchen, stellt sich heraus, dass der Winkelmesser nur in Knoten läuft, alles, was Sie tun müssen, ist var helpers = require('./your-helper-file').

+0

hmm .. könnten Sie das näher ausführen? Ich habe begonnen, Winkelmesser zu verwenden, aber ich habe fast keine Erfahrung in Knoten. Muss ich etw konfigurieren? – WeMakeSoftware

+0

@Funtik Sie müssen die Methoden innerhalb der "your-helper-file.js" wie in dieser Antwort hinzufügen: http://Stackoverflow.com/a/5311377/3111930 * Edit: ah okay, Sie antworteten sich :-) – Sebastian

2

ich mich in der gleichen Sache bin auf der Suche, und zu einem gewissen Grad hatte ich gehofft, dass Sie eine Antwort für mich zu dieser Frage haben würden. :-)

Nachdem gesagt, dass Winkelmesser ist neu genug, dass niemand wirklich die Antwort kennt, und ich denke, das macht meine Antwort so gut wie die nächsten Personen.

Zunächst verwende ich die Seite Object Notation, die auf dem Transporteur beschrieben Seite der ersten Schritte, nach unten hin: https://github.com/angular/protractor/blob/master/docs/getting-started.md

Das gibt ein Element der Modularität, hier meine Meinung ist, dass ich mit einem Ende Reihe von Klassen, eine pro Seite, die einige der Details abstrahieren. So könnte ich zum Beispiel eine "foo" Klasse haben, die Abstraktionen wie "foo.get" und "foo.validate (id, name, otherData)" enthält. Dies wäre eine Möglichkeit, wiederholten Code herauszuziehen.

Das Bit, das ich nicht ausgearbeitet habe, ist, wie man eine Bibliothek von Modulen erstellt und diese dann zu einem einzigen Satz von Szenarien zusammensetzt. Ich habe ein paar Gedanken aber:

  1. Das zugrunde liegende Problem ist die Fähigkeit, Javascript-Dateien in einander zu integrieren - die wirklich nicht als eine Fähigkeit existiert. Es gibt Bibliotheken von Drittanbietern, die ich lieber nicht benutzen würde, und ich habe keine Möglichkeit gesehen, die Modulfähigkeit von Angular dafür zu nutzen.
  2. End-2-Endtest kann sehr von der Reihenfolge der Tests abhängig sein. So kann ein Test Daten erzeugen, ein anderer Test kann diese Daten dann verwenden. Wenn Sie beispielsweise einen Test verwenden möchten, bei dem Personen angemeldet sind, benötigen Sie möglicherweise einen Test, bei dem zuerst Personen registriert werden. Wahrscheinlich möchten Sie die Registrierung nicht bei jedem Test, den Sie ausführen, in den Vordergrund stellen. Daher benötigen Sie wahrscheinlich eine Menge Kontrolle über die Reihenfolge Ihrer Testszenarien.
  3. Als solche ist eine Option, einfach alles in eine wirklich große Datei zu stellen. Was gegen alles ist, was wir alle in der Schule gelernt haben, aber ich habe nicht wirklich einen Grund gefunden, der nicht funktionieren würde. Dann können Sie Funktionen und Abstraktionen nach Herzenslust schreiben.
  4. Wenn Sie dies zur nächsten Stufe folgen, besteht eine andere Möglichkeit darin, eine Reihe von Javascript-Dateien mit strengen Namenskonventionen zu schreiben, dann verwenden Sie grunt, um sie für Sie zu verketten, bevor Sie sie ausführen. So zum Beispiel:
    • Eine Reihe von Dateien mit dem Namen xxxx.page.scenario.js, die die „Seitenobjekt“ Definitionen enthalten - im Grunde Hilfsmethoden für jede Seite
    • Eine Reihe von Dateien mit dem Namen xxxx.functions.scenario .js, die gemeinsame Komponenten Ihrer Szenarios enthalten - also haben Sie möglicherweise eine Register- und Anmeldungsmenge von Aktionen, und Sie machen diese in eine Bibliotheksfunktion
    • Eine Reihe von Dateien namens nnxx.scenarios.scenario.js, die die tatsächliche Skripte selbst.Diese werden zu Beginn (die nn) nummeriert, so dass wir sie in einer zuverlässigen Folge verketten und dadurch steuern, die bestellen Sie unsere Skripte laufen

Ich bin noch nicht sagen, das ist eine gute Idee, nur dass es zumindest oberflächlich aussieht, als könnte es funktionieren, und würde das gewünschte Ergebnis geben. Mein Hauptanliegen ist, dass es sich zerbrechlich anfühlt. Wenn die Testsuite größer wird, wird sie vielleicht sehr schwierig zu warten sein. Eine andere Möglichkeit wäre, anstatt die Szenarien zu nummerieren, diese stattdessen als Abhängigkeiten zu definieren und sicherzustellen, dass jedes Skript nach einem Skript ausgeführt wird, von dem es sich selbst abhängig macht. Das würde vielleicht auch eine Teilmenge der Skripte erlauben - also könnte man sagen "führe das Bar-Skript aus" und das Framework würde wissen, dass das Bar-Skript zuerst das foo-Skript ausführen muss und vielleicht das Login-Skript. Aber es ist in Ordnung, alle anderen Skripte auszulassen.

EDIT: Ich sehe Astrolabium als potentiell eine gute Antwort hier, es sieht aus wie es ausdrücklich erlaubt Ihnen, Ihre Tests zu modularisieren. https://github.com/stuplum/astrolabe. Ich habe gerade einen Proof of Concept damit abgeschlossen und es scheint alles zu tun, was ich hoffen könnte. Der Code für es am Ende so etwas wie:

clubs.part.scenario.js:

/** 
* Partial for the page objects associated with clubs 
*/ 
var Page = require('astrolabe').Page; 

module.exports = Page.create({ 
    url: { value: 'UI/index.html#clubs' }, 
    title: { get: function() { return this.findElement(this.by.id('title')); } }, 
    description: { get: function() { return this.findElement(this.by.id('description')); } }, 
    clubTableElement: { value: function(rowNum, columnBinding) { 
    return this.findElement(this.by.repeater('club in clubs').row(rowNum).column(columnBinding)); } } 
    } 
); 

clubs.scenario.js:

/** 
* End to end tests for the club functionality 
*/ 

var homePage = require('../home/home.part.scenario.js'); 
var clubsPage = require('./clubs.part.scenario.js'); 

describe('Navigate to club list page', function() { 
    it ('should allow navigation to the club list page', function() { 

    homePage.go(); 
    expect(homePage.clubsLink.getText()).toEqual('Clubs'); 

    homePage.clubsLink.click(); 

    expect(clubsPage.title.getText()).toEqual('Club functions'); 
    expect(clubsPage.description.getText()).toEqual('Soon this will show a list of all the clubs, based on information from the server'); 
    expect(clubsPage.clubTableElement(0, 'name').getText()).toEqual('First club');  
    expect(clubsPage.clubTableElement(0, 'contact_officer').getText()).toEqual('A Person');  
    expect(clubsPage.clubTableElement(1, 'name').getText()).toEqual('Second club');  
    expect(clubsPage.clubTableElement(1, 'contact_officer').getText()).toEqual('J Jones');  
    }); 

    it ('should allow us to go directly to the club list page', function() { 
    clubsPage.go(); 

    expect(clubsPage.title.getText()).toEqual('Club functions'); 
    expect(clubsPage.description.getText()).toEqual('Soon this will show a list of all the clubs, based on information from the server'); 
    expect(clubsPage.clubTableElement(0, 'name').getText()).toEqual('First club');  
    expect(clubsPage.clubTableElement(0, 'contact_officer').getText()).toEqual('A Person');  
    expect(clubsPage.clubTableElement(1, 'name').getText()).toEqual('Second club');  
    expect(clubsPage.clubTableElement(1, 'contact_officer').getText()).toEqual('J Jones');  
    }); 
}); 

Ich bin ziemlich glücklich mit dieser Struktur, Es macht nicht alles, aber es macht die meisten Dinge. Der Beispielcode, den ich zur Verfügung gestellt habe, stammt aus dem Tutorial, mit dem ich seit einiger Zeit arbeite, mit angularjs, das ich gerade für e2e testing und Rails 4 aktualisiere, wenn du den Kontext dazu haben willst: http://technpol.wordpress.com/2013/11/16/5-end-to-end-testing/

+0

Weiter zu diesem, ich sehe dies: https://github.com/dmitrybelyakov/protractor/blob/Feature/PageObject/docs/ page-object.md, das eine Abstraktionsebene bietet und das Teilen von Testfällen erlaubt (glaube ich). Und auch Astrolabium, das explizit das Teilen von Inhalten zuzulassen scheint: https://github.com/stuplum/astrolabe – PaulL

+0

Paul, danke für eine wirklich gute Antwort! Hatte heute einen Blick auf Astrolabium und es sieht aus wie etwas, das ich gerne verwenden würde. Bis jetzt werde ich bei Option 3 bleiben, da ich immer noch dabei bin, Winkelmesser und JavaScript zu lernen :-) – Annie

+0

Ich habe weitere Fortschritte im Astrolabieren gemacht, seit ich das geschrieben habe - ich denke ich bin in einem ähnlichen Punkt wie du der Lebenszyklus. Ich habe es in meiner echten App laufen lassen (im Gegensatz zum Tutorial) und es funktioniert sehr gut. Und, um ehrlich zu sein, es war wirklich sehr einfach zu installieren. Ich würde es versuchen, anstatt später umgestalten zu müssen. – PaulL

14

Basierend auf der @ Langliman Antwort, habe ich es geschafft, das gewünschte Verhalten zu erreichen.

Hinweislogin.spec.js und Login.page.js sollten sich im selben Ordner befinden.

Login.page.js Datei:

var LoginPage = function (ptor) { 
    //following PageObject pattern define the functions here. 
} 

module.exports.getLoginPage = function (ptor) { 
    return new LoginPage(ptor); 
}; 

login.spec.js Datei:

(function() { 
    'use strict'; 

    describe('login page', function() { 

     var ptor = protractor.getInstance(); 
     var loginPageBuilder = require('./Login.page.js'); 
     var loginPage = loginPageBuilder.getLoginPage(ptor); 

     it('should login as admin', function() { 
      loginPage.visit(); 
      loginPage.enterUsername('user'); 
      loginPage.enterPassword('password'); 
      loginPage.login(); 
     }); 
    }); 

}()); 
+0

Freut mich zu sehen, dass du es herausgefunden hast ... sieht gut aus. – iangilman

+0

Vielen Dank für das Schreiben eines Beispiels – bitwit

+0

Erprobt das gleiche Verfahren. aber kann immer noch nicht die Funktionen aus meiner Seite Objektdatei aufrufen. irgendwelche Änderungen/Alternativen dazu? – Prem

5

Falls Sie Setup und vor/nach Funktionen sowie Hilfsmethoden Nutzer sichtbar sein, ein Lösung besteht darin, die Tests von Ihrem Spezifikationshelfer zu verlangen, anstatt Ihren Spezifikationshelfer von den Tests zu erfordern.

conf.js

exports.config = { 
    seleniumAddress: 'http://localhost:4444/wd/hub', 
    specs: ['e2e/spec.js'] 
} 

e2e/spec.js

var chai = require('chai'), 
    homepage = require('./homepage.js'), 
    signin = require('./signin.js'); 

chai.should() 
browser.baseUrl = 'http://localhost:3000' 

homepage.test() 
signin.test() 

e2e/Homepage.js

exports.test = function() { 
    describe('homepage', function() { 
    it('should have the right title', function() { 
     browser.get('/') 

     browser.getTitle().then(function(title){ 
     title.should.eq('Home') 
     }) 
    }); 
    }); 
} 

e2e/signin.js

exports.test = function() { 
    describe('signin', function() { 
    it('should have the right title', function() { 
     browser.get('/signin') 

     browser.getTitle().then(function(title){ 
     title.should.eq('Sign in') 
     }) 
    }); 
    }); 
} 
Verwandte Themen