LoginSignup
2

More than 5 years have passed since last update.

posted at

React Native - Integration Test

昨日のUnitテストが若干結合テストを含んでいたことは置いといて, 今日はIntegration Testを説明します。

結合テスト

公式ドキュメントにもあるように現時点ではiOSのみです。このテストは、XcodeのテストとJSとのコンビネーションで実現しています。

環境設定

(少し前に設定したので、忘れてる部分があるかもしれません。ご容赦ください)

1. iOS Unit test bundleを追加

スクリーンショット 2015-12-16 10.44.06.png

2. Linking library

node_modules/react-native/Libraries/RCTTest/RCTTest.xcodeprojをリンクさせる。Xcodeの左のペインにドラックアンドドロップする。詳しくはこちら

step1
スクリーンショット 2015-11-07 8.37.57.png

step2
スクリーンショット 2015-11-07 8.39.07.png

3. テストファイル(*.m)を書き換える

#import <UIKit/UIKit.h>
#import <XCTest/XCTest.h>

#import <RCTTest/RCTTestRunner.h>

#import "RCTAssert.h"

#define RCT_TEST(name)                  \
- (void)test##name                      \
{                                       \
[_runner runTest:_cmd module:@#name]; \
}

@interface TriplentyIntegrationTests : XCTestCase

@end


@implementation TriplentyIntegrationTests
{
  RCTTestRunner *_runner;
}

- (void)setUp
{
#if __LP64__
  RCTAssert(NO, @"Tests should be run on 32-bit device simulators (e.g. iPhone 5)");
#endif

  NSOperatingSystemVersion version = [NSProcessInfo processInfo].operatingSystemVersion;
  RCTAssert((version.majorVersion == 8 && version.minorVersion >= 3) || version.majorVersion >= 9, @"Tests should be run on iOS 8.3+, found %zd.%zd.%zd", version.majorVersion, version.minorVersion, version.patchVersion);
  _runner = RCTInitRunnerForApp(@"iOS/TriplentyIntegrationTests/js/IntegrationTestsApp", nil);
}

#pragma mark Logic Tests


// This list should be kept in sync with IntegrationTestsApp.js
RCT_TEST(IntegrationTestHarnessTest)
RCT_TEST(TriplentyTest)
//RCT_TEST(AsyncStorageTest)
//RCT_TEST(AppEventsTest)
////RCT_TEST(ImageSnapshotTest) // Disabled: #8985988
//RCT_TEST(SimpleSnapshotTest)

// Disable due to flakiness: #8686784
//RCT_TEST(LayoutEventsTest)
//RCT_TEST(PromiseTest)

@end

4. JSファイルを作る

iOS/<target test name>/js/ディレクトリを作り、3)のRCT_TESTの引数のファイル名を作る。例にもある下記のIntegrationTestHarness.jsでテストがうまくいっているかXcodeのテストを起動して確認します。

'use strict';

var RCTTestModule = require('NativeModules').TestModule;
var React = require('react-native');
var {
  Text,
  View,
} = React;

var IntegrationTestHarnessTest = React.createClass({
  propTypes: {
    shouldThrow: React.PropTypes.bool,
    waitOneFrame: React.PropTypes.bool,
  },

  getInitialState() {
    return {
      done: false,
    };
  },

  componentDidMount() {
    if (this.props.waitOneFrame) {
      requestAnimationFrame(this.runTest);
    } else {
      this.runTest();
    }
  },

  runTest() {
    if (this.props.shouldThrow) {
      throw new Error('Throwing error because shouldThrow');
    }
    if (!RCTTestModule) {
      throw new Error('RCTTestModule is not registered.');
    } else if (!RCTTestModule.markTestCompleted) {
      throw new Error('RCTTestModule.markTestCompleted not defined.');
    }
    this.setState({done: true}, RCTTestModule.markTestCompleted);
  },

  render() {
    return (
      <View style={{backgroundColor: 'white', padding: 40}}>
        <Text>
          {this.constructor.displayName + ': '}
          {this.state.done ? 'Done' : 'Testing...'}
        </Text>
      </View>
    );
  }
});

IntegrationTestHarnessTest.displayName = 'IntegrationTestHarnessTest';

module.exports = IntegrationTestHarnessTest;

OKだったら、下記のようにコンポーネントを呼び込み下記のような感じで動かします。TestModule.markTestPassed(true)で成功、TestModule.markTestPassed(false)で失敗を呼べます。

'use strict';
import UserActions from 'Triplenty/app/actions/UserActions';
import UserStore from 'Triplenty/app/stores/UserStore';
import TabBarView from 'Triplenty/app/components/TabBarView';
import Triplenty from 'Triplenty/app/Triplenty';
import React from 'react-native';
var { TestModule } = React.addons;

var TriplentyTest = React.createClass({

  login(){
    let fbObj = { ... }
    UserActions.parseSignIn(fbObj);
  },

  componentDidMount() {
    this.unsubscribe = UserStore.listen(this.onUserUpdated);
    UserActions.parseLogOut();
    this.login();
  },

  onUserUpdated(){
    this.done(true);
  },

  done(success) {
    TestModule.markTestPassed(success);
  },

  render() {
    return (
      <Triplenty/>
    );
  }
});

TriplentyTest.displayName = 'TriplentyTest';

module.exports = TriplentyTest;

Summary

結合テストではシミュレータが起動してテストできます。上の例ではReduxを利用していませんが、Reduxの状態とActionをうまいこと利用すれば、内部状態のテストもできると思います。

Appendix

appiumを利用したIntegrationテストの記事を見つけました。参考までに。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
2