短い回答:模擬それ。 =)
長い回答:できるだけ多くのテストで実際のコード(すなわち、テストダブルを含まない)を使用することを個人的に好みます。しかし、時にはそれだけの価値がないし、あなたは嘲笑に落ちる必要があります。
- いくつかのサブサンクが、実際にテスト中のあなたのサンクから派遣されたこと:あなたは/あなたのテストで確認する必要がある場合がありますいくつかのものがある上記のようなケースで
。
- テスト中のサンクは、ディスパッチするサブサンクの結果を正しく処理します。
- テスト中のサンクは、ディスパッチされたサブサンクによって更新された更新された状態を正しく処理します。
あなたが上記のどの組み合わせをテストするかによって、異なる戦略を使用することができます。たとえば、テスト対象のサンクがサブサンクの結果に依存している場合に、サブサンクが送出されたかどうかを確認する必要はありません。特定のサンクのテスト結果の動作に影響する特定のデータを返すように、分かりやすい方法(下記のスニペットの詳細についてはauth
モックを参照してください)。
可能性のある模擬戦略を説明するために、次の例を考えてみましょう。認可機能を実装する必要があるとします。あなたのサーバーがhttpエンドポイント経由でユーザーを認証し、成功した場合、後でwebsocket接続を開くために使用される認証トークンを送り返すとしましょう。
connect
サンクがあり、ユーザーのログインとパスワードでauth
サブサンクを送信し、httpで指定の資格情報を送信します。サーバーが応答するとauth
サンクはstore
のトークンを受信して格納します(説明の都合上)。 auth
が解決すると、connect
がトークンで他のものを実行するotherStuff
サンクをディスパッチします。最後にconnect
はwsApi
でソケット接続を開きます。 auth
とotherStuff
:我々はつもりです何
// ======= connect.js =======
import { auth, getToken } from './auth';
import * as wsApi from './ws';
import { otherStuff } from './other-stuff';
export const connect = (login, password) => (dispatch, getState) => {
// ...
return dispatch(auth(login, password))
.then(() => {
const token = getToken(getState());
dispatch(otherStuff(token));
wsApi.connect(token);
});
// ...
};
// ======= auth.js =======
import * as httpApi from './http';
const saveToken = token => ({ type: 'auth/save-token', payload: token });
export const auth = (login, password) =>
dispatch =>
httpApi.login(login, password)
.then(token => dispatch(saveToken(token)));
export const getToken = state => state.auth.token;
export default (state = {}, action) => action.type === 'auth/save-token' ? { token: action.payload } : state;
// ======= other-stuff.js =======
export const otherStuff = token => (dispatch) => {
// ...
};
は2つのサンクを模擬することです。 connect
はauth
に大きく依存していますので、私たちはauth
に渡した模擬動作に応じて、auth
がちょうどチェックconnect
の動作によって呼び出されるようにします。 otherStuff
の場合は少し複雑です。それが実際に他のディスパッチされたアクションをログに記録するカスタムミドルウェアを実装していないかどうかを確認する方法はありません。 (私はあざけるためjestを使用しています)、次のようにすべてのテストのすべてが表示されます:あなたが与えられたスニペット上の任意のコメントが必要な場合は
import { createStore, applyMiddleware, combineReducers } from 'redux';
import thunk from 'redux-thunk';
import { connect } from './connect';
import { auth, getToken } from './auth';
import { otherStuff } from './other-stuff';
import * as wsApi from './ws';
const authReducer = require.requireActual('./auth').default;
jest.mock('./auth');
jest.mock('./ws');
jest.mock('./other-stuff');
const makeSpyMiddleware =() => {
const dispatch = jest.fn();
return {
dispatch,
middleware: store => next => action => {
dispatch(action);
return next(action);
}
};
};
describe('connect',() => {
let store;
let spy;
beforeEach(() => {
jest.clearAllMocks();
spy = makeSpyMiddleware();
store = createStore(authReducer, {}, applyMiddleware(spy.middleware, thunk));
auth.mockImplementation((login, password) =>() => {
if (login === 'user' && password == 'password') return Promise.resolve();
return Promise.reject();
});
});
test('happy path',() => {
getToken.mockImplementation(() => 'generated token');
otherStuff.mockImplementation(token => ({ type: 'mocked/other-stuff', token }));
return store.dispatch(connect('user', 'password')).then(() => {
expect(wsApi.connect).toHaveBeenCalledWith('generated token');
expect(spy.dispatch).toHaveBeenCalledWith({ type: 'mocked/other-stuff', token: 'generated token'});
});
});
test('auth failed',() => {
return store.dispatch(connect('user', 'wrong-password')).catch(() => {
expect(wsApi.connect).not.toHaveBeenCalled();
});
});
});
は、お気軽に。
すべてのユースケースでお手伝いできますが、ミドルウェアを使用することを検討しているかどうか不明ですか? –