2017-03-08 5 views
1

ここでは、Mocha/Chaiで書いたテストスタブを示します。私はアクションを簡単に送信でき、状態は私が期待しているものと同等であると主張しますが、途中で期待されるプロセス(IEの以前のテスト)に従ったことをどのように検証しますか?redux-thunkを使用するreduxアプリケーションを単体テストする方法

/** 
* This test describes the INITIALIZE_STATE action. 
* The action is asynchronous using the async/await pattern to query 
* The database. The action creator returns a thunk which should in turn 
* return the new state with a list of tables and their relationships with eachother 
**/ 

describe('Initialize state',() => { 
    it('Should check if state is empty',() => {}); 
    it('Should check if tables/relationships exist',() => {}); 
    it('Should check if new tables have been added',() => {}); 
    it('Should merge new and existing tables and relationships',() => { 
     // Here is where we would dispatch the INITIALIZE_STATE 
     // action and assert that the new state is what I expect it to be. 
    }); 
}); 

実際のアクション自体のコードはまだ書かれていません。これらの検証にコードを渡したいからです。いくつかの擬似コードはこのように見えるかもしれません。

export function initializeState() { 
    return function(dispatch) { 
     let empty = store.getState().empty 
     let state = (empty) ? await getLastPersistedState() : store.getState() 
     let tables = state.tables; 
     let payload = tables.concat(await getNewTables(tables)); 
     dispatch({type: 'INITIALIZE_STATE', payload}); 
    } 
} 

function getLastPerisistedState() { 
    return mongodb.findall(state, (s) => s); 
} 

function getNewTables(tableFilter) { 
    return sql.query("select table_name from tables where table_name not in (" + tableFilter + ")"); 
} 
+0

実際のmongo/SQL関数を呼び出したいのですか?私の標準的なアプローチは、テストを必要としないように非同期のもの(ここではサンク)を短くし、その周りのすべてをテストすることです。 'INITIALIZE_STATE'アクションを模擬ペイロードでテストしてください。 – nrabinowitz

答えて

0

ここに私が思いついた解決策があります。より良いものがあるかもしれませんが、これまで誰も提供することはできませんでした。私は、リファクタリングされた一連のアクションと、私のテストのための別のストアに行くことに決めました。このアクションは、サンクを使用するのではなく、関数ジェネレータです。サンクがプロダクションコードに送り出すアクションを生成します。私のテストでは、これらのアクションを自分でディスパッチして、結果の状態が私が期待しているものであることを確認できます。これはまさにサンクがすることですが、それは私がサンドのミドルウェアに依存するよりもむしろ中間の人間として自分自身を挿入することができます。

これは、非同期フローをテストしているときでも、アクションロジックとディスパッチロジックおよびステートロジックを非常に簡単に分離できるため、非常に便利です。

データベースの場合、私は自動的にスタブを生成し、非同期クエリをシミュレートする約束を使用します。このプロジェクトでは続編を使用しているので、私はスタブを生成するために続編を使用しました。ここ

コード

_actions.js

export function *initializeState() { 
    //We will yield the current step so that we can test it step by step 

    //Should check if state is empty 
    yield {type: 'UPDATE_STEP', payload: 'IS_STATE_EMPTY'}; 
    yield {type: 'UPDATE_STEP_RESULT', payload: stateIsEmpty()}; 

    if(stateIsEmpty()) { 
     //todo: Implement branch logic if state is empty 
    } 
    //... 
} 

sequelize/_test/generate.js

async function createMockFromSql(db, sql, filename) { 
    let results = await db.query(sql, {type: db.Sequelize.QueryTypes.SELECT}); 
    return new Promise((resolve, reject) => { 

     // Trim the results to a reasonable size. Keep it unique each time 
     // for more rigorous testing 

     console.log('trimming result set'); 
     while (results.length > 50) { 
      results.splice(results.length * Math.random() | 0, 1); 
     } 

     fs.writeFile(path.resolve(__dirname, '../../sequelize/_test', filename), JSON.stringify(results, null, 2), err => { 
      if (err) { 
       console.error(err); 
       reject(false); 
      } 

      resolve(true); 
     }) 
    }) 
} 

テスト/

01 actions.jsあります
... 
it('Should check if state is empty',() => { 
    let action = initializeState(); 
    expect(action.next()).to.deep.equal({type: 'UPDATE_STEP', payload: 'IS_STATE_EMPTY'}) 
}); 
関連する問題