1

私の質問の短いバージョン:

Angular シングル ページ Web アプリケーション用に記述された Cucumber テストでは、シナリオの「指定された」セクションで通常実行されるタスク (テスト データの設定、データベース レコードの関連付けの定義、テスト間のクリーンなデータベース状態の確保など) をどのように達成するのですか? ) フルスタックをテストするとき、フロントエンド アプリケーションとそのバックエンドの両方? アプリケーションのソース コードは、フロントエンド アプリケーション用とバックエンド用の 2 つの個別の Git リポジトリに格納されます。バックエンドは、Rails API gem を使用して Ruby で記述されています。このアプリケーションのフルスタックをテストする際の課題は、シングル ページ アプリケーションとして実装されていない従来の Ruby on Rails アプリケーションとは対照的に、実際には 2 つのアプリケーションであるという事実から生じます。

私の質問の完全版:

Web アプリケーション用の一連の Cucumber テストを作成しようとしています。このアプリケーションは、Angular で記述されたフロントエンドの単一ページ アプリケーションと、Rails API を使用して記述されたバックエンド API で構成されています。フロントエンドのソース コードとバックエンドのソース コードはそれぞれ独自の Git リポジトリに存在するため、2 つのコードベースが明確に分離されています。さらに、アプリケーションは MySQL と Elasticsearch を使用します。

以前の Ruby on Rails プロジェクトで Cucumber を使用したことがあります。これらのプロジェクトは、単一ページのアプリケーションとして開発されたものではありません。これらのプロジェクトでは、Ruby オブジェクトを Cucumber ステップ定義のテスト データとして簡単に作成できました。たとえば、シングル ページ アプリケーションではない Rails プロジェクトの次の機能ファイルについて考えてみましょう。

# features/home_page.feature
Feature: Home page

  Scenario: Viewing application's home page
    Given there's a post titled "My first" with "Hello, BDD world!" content
    When I am on the homepage
    Then I should see the "My first" post

この機能ファイルのステップは、次のステップ定義を使用して実装できます。

# features/step_definitions/home_page_steps.rb
Given(/^there's a post titled "(.*?)" with "(.*?)" content$/) do |title, content|
  @post = FactoryGirl.create(:post, title: title, content: content)
end

When(/^I am on the homepage$/) do
  visit root_path
end

Then(/^I should see the "(.*?)" post$/) do |title|
  @post = Post.find_by_title(title)

  page.should have_content(@post.title)summary of the question
  page.should have_content(@post.content)
end

シングル ページ アプリケーションとして開発されていない Ruby on Rails プロジェクトでは、テスト ツールを Ruby gem としてプロジェクトに含めることができます。私にとって、これらのツールには次のものが含まれます。

group :test do
  gem 'shoulda-matchers'
  gem 'cucumber-rails', require: false
  gem 'database_cleaner'
  gem 'selenium-webdriver'
end

group :development, :test do
  gem 'factory_girl_rails'
end

ご覧のとおり、これには、Ruby オブジェクトをテスト データとして設定し、データベース レコードの関連付けを定義するために使用される Factory Girl と、テスト間でクリーンなデータベース状態を確保するために使用される Database Cleaner が含まれます。JavaScript を使用する Cucumber シナリオでは、Selenium WebDriver を含める必要があります。

私のシングルページアプリケーションの場合は状況が異なります。前述のように、アプリケーションは 2 つの別個のコード ベースに分割されます。1 つは Angular フロントエンド シングル ページ アプリケーション用で、もう 1 つは Rails API バックエンド インターフェイス用です。

ただし、私のプロジェクトのようなシングル ページ アプリケーションには、シングル ページ アプリケーションとして構築されていない従来の Rails アプリケーションと同じテスト要件がまだあります。アプリケーションのフルスタックをテストして、フロントエンドとバックエンドの両方の各コンポーネントが期待どおりに連携することを確認する必要があります。テストの前に「与えられた」前提条件を作成する Cucumber ステップを定義する必要があり、テスト間でクリーンなデータベースを確保する必要があります。

このような 2 つのコード ベースを持ち、単一ページ アプリケーションとして実装されたアプリケーションを Cucumber でテストするにはどうすればよいですか? CucumberJS と呼ばれる JavaScript で利用できる Cucumber のバージョンがあります。ただし、CucumberJS を使用して、フィクスチャを作成し、関連付けを記録し、テスト間でクリーンなデータベースを確保する方法がわかりません。Protractor と呼ばれる、Angular で記述された JavaScript をテストするためのツールもあります。このツールが Selenium WebDriver の代わりになると思います。

4

1 に答える 1

0

短いバージョンの質問に答えます。

このアプリケーションのフルスタックをテストする際の課題は、実際には 2 つのアプリケーションであるという事実から来ています。

あなたが説明することは、単一ページのアプリに典型的です。バックエンドが PHP の RESTful API、Dot.net、またはクラウド Web サービス (parse.com) であるスパの例 (E2E でカバー) がいくつかあります。私の見解では、このようなアプリを 2 つの異なるアプリとして扱い、それぞれに対して 2 つの異なるテスト セットを作成するのが最善です。それが、安定した、スケーラブルで高速な e2e テストを作成する唯一の方法だと思います。

基本的に、特にテスト用にローカルの非永続的なモック API (javascript で) を作成します。このような API の要件/ガイドラインのリストは次のとおりです。

  1. テスト スーツのモック データを提供します (読み取り - テスト スーツと結合されます)。
  2. テストに合格するのに十分なメソッドをカバーします。
  3. 永続的ではありません (例外はありますが、応答を行うために必要なのは要求パラメーターだけです)。すべての永続性はクライアントにあります (localstorage、cookie)。クライアント ストレージをクリアしてページを更新するだけで、アプリの最新の状態が得られるため、これは重要です。モノリスをテストする場所 - データベースをクリアして再作成する必要がありますが、これは時間の無駄であり、完全にスケーラブルではありません。
  4. angular リポジトリに組み込まれており、テスト スイートおよび開発プロセスの一部です。

それは実際にはどのように見えますか。Web サイトのログイン機能をテストしていて、3 つのシナリオがあるとします。

var homepage = require('pages/homepage'); //page object for home page

describe('Authentication', function () {

  beforeEach(function () {
    browser.manage().deleteAllCookies(); //clear persistance
    browser.refresh(); //refresh page
    homepage.get(); //go to homepage
  });

  it('should show error when user enters wrong credentials', function () {
    homepage.signIn('admin', '123'); //submit invalid credentials 
    expect(browser.getCurrentUrl()).toMatch('/home$');    
    expect(homepage.getSignInForm()).toContain('wrong credentials');
  });

});

これらのテストを満たすには、POST /login リクエスト用の API を実装するだけです。

router.get('/login', function (req, res) {
  var username = req.body.username, password = req.body.password;

  if (password !== 'admin') {
    res.status(404).json({"error": "wrong credentials"});
  } else {
    res.json(User(username}));
  }
});
于 2015-06-15T12:18:58.080 に答える