2016-02-26 23 views
22

Tôi đang cố gắng kiểm tra mọi tình huống mà câu chuyện của tôi có thể theo dõi, nhưng tôi không thể thực hiện các hành vi tôi muốn. Điều này khá đơn giản, tôi có một yêu cầu HTTP (đăng nhập), và tôi muốn kiểm tra sự thành công và các trường hợp thất bại bằng cách chế nhạo phương thức API của tôi. Tuy nhiên, có vẻ như call effect không kích hoạt chức năng api của tôi, tôi vẫn chưa thực sự hiểu nó hoạt động như thế nào, nhưng tôi đoán rằng phần mềm trung gian chịu trách nhiệm gọi hàm, và vì tôi không mặc dù các cửa hàng trên thử nghiệm của tôi, tôi không thể có được kết quả.Làm cách nào để kiểm tra lỗi yêu cầu API với Redux Saga?

Vì vậy, câu hỏi của tôi là, làm thế nào bạn có thể kiểm tra saga của bạn khi bạn cần phải gửi các hành động khác nhau (thường thành công hay thất bại) bên cạnh cuộc gọi không đồng bộ của bạn?

Tôi nhìn cho một ví dụ, tôi thấy saga với thành công và thất bại nhưng trường hợp thất bại không bao giờ được thử nghiệm, ví dụ như trong ví dụ giỏ hàng here

SAGA.JS

export function* login(action) { 
    try { 
    const user = yield call(api.login, action); 
    return yield put(actions.loginSuccess(user)); 
    } catch(e) { 
    yield put(actions.loginFail(e)); 
    } 
} 

export default function* rootAuthenticationSagas() { 
    yield* takeLatest(LOGIN, login); 
} 

test.js

describe('login',() => { 
    context('When it fails',() => { 
    before('Stub the api',() => { 
     sinon.stub(api, 'login',() => { 
     // IT NEVER COMES HERE ! 
     return Promise.reject({ error: 'user not found' }); 
     }); 
    }); 

    it('should return a LOGIN_FAIL action',() => { 
     const action = { 
     payload: { 
      name: 'toto', 
      password: '123456' 
     } 
     }; 
     const generator = login(action); 

     // THE CALL YIELD 
     generator.next(); 

     const expectedResult = put({ type: 'LOGIN_FAIL', payload: { error: 'user not found' } }); 
     expect(generator.next().value).to.be.eql(expectedResult); // FAIL BECAUSE I GET A LOGIN_SUCCESS INSTEAD OF A FAIL ONE 
    }); 
    }); 
}); 

Trả lời

36

Mark’s answer là chính xác. Middleware thực hiện các hướng dẫn đó. Nhưng điều này làm cho cuộc sống của bạn dễ dàng hơn: trong thử nghiệm, bạn có thể cung cấp bất cứ điều gì bạn muốn làm đối số cho next() và chức năng trình phát sẽ nhận được kết quả là yield. Đây là chính xác những gì saga middleware hiện (ngoại trừ việc nó thực sự kích hoạt một yêu cầu thay vì cho bạn một phản ứng giả).

Để thực hiện yield nhận giá trị tùy ý, hãy chuyển nó tới next(). Để làm cho nó "nhận" một lỗi, vượt qua nó để throw(). Trong ví dụ của bạn:

it('should return a LOGIN_FAIL action',() => { 
    const action = { 
    payload: { 
     name: 'toto', 
     password: '123456' 
    } 
    }; 
    const generator = login(action); 

    // Check that Saga asks to call the API 
    expect(
    generator.next().value 
).to.be.eql(
    call(api.login, action) 
); 

    // Note that *no actual request was made*! 
    // We are just checking that the sequence of effects matches our expectations. 

    // Check that Saga reacts correctly to the failure 
    expect(
    generator.throw({ 
     error: 'user not found' 
    }).value 
).to.be.eql(
    put({ 
     type: 'LOGIN_FAIL', 
     payload: { error: 'user not found' } 
    }) 
); 
}); 
7

Đúng - như tôi đã hiểu, toàn bộ điểm của Redux-Saga là hàm saga của bạn sử dụng API saga để trả về các đối tượng mô tả thứ e hành động, và sau đó các phần mềm trung gian sau đó nhìn vào những đối tượng để thực sự thực hiện hành vi. Vì vậy, một tuyên bố yield call(myApiFunction, "/someEndpoint", arg1, arg2) trong một câu chuyện có thể trả về một đối tượng trông giống như {effectType : CALL, function: myApiFunction, params: [arg1, arg2]}.

Bạn có thể kiểm tra nguồn redux-saga để xem chính xác những đối tượng khai báo đó thực sự trông như thế nào và tạo đối tượng phù hợp để so sánh trong thử nghiệm của bạn hoặc sử dụng các hàm API để tạo đối tượng. những gì redux-saga làm trong mã thử nghiệm của họ).

0

Bạn cũng có thể muốn sử dụng một thư viện helper để kiểm tra saga của bạn, chẳng hạn như redux-saga-testing.

Disclaimer: Tôi đã viết thư viện này để giải quyết cùng một vấn đề chính xác

Thư viện này sẽ làm cho cái nhìn thử nghiệm của bạn giống như bất kỳ khác (đồng bộ) kiểm tra, đó là dễ dàng hơn nhiều để suy luận về vì gọi generator.next() bằng tay.

Lấy ví dụ của bạn, bạn có thể viết các bài kiểm tra như sau:

(nó sử dụng cú pháp đùa, nhưng đó là về cơ bản giống với Mocha, nó hoàn toàn kiểm tra thư viện-agnostic)

import sagaHelper from 'redux-saga-testing'; 
import { call, put } from 'redux-saga/effects'; 
import actions from './my-actions'; 
import api from './your-api'; 

// Your example 
export function* login(action) { 
    try { 
     const user = yield call(api.login, action); 
     return yield put(actions.loginSuccess(user)); 
    } catch(e) { 
     yield put(actions.loginFail(e.message)); // Just changed that from "e" to "e.message" 
    } 
} 


describe('When testing a Saga that throws an error',() => { 
    const it = sagaHelper(login({ type: 'LOGIN', payload: 'Ludo'})); 

    it('should have called the API first, which will throw an exception', result => { 
     expect(result).toEqual(call(api, { type: 'LOGIN', payload: 'Ludo'})); 
     return new Error('Something went wrong'); 
    }); 

    it('and then trigger an error action with the error message', result => { 
     expect(result).toEqual(put(actions.loginFail('Something went wrong'))); 
    }); 
}); 

describe('When testing a Saga and it works fine',() => { 
    const it = sagaHelper(login({ type: 'LOGIN', payload: 'Ludo'})); 

    it('should have called the API first, which will return some data', result => { 
     expect(result).toEqual(call(api, { type: 'LOGIN', payload: 'Ludo'})); 
     return { username: 'Ludo', email: '[email protected]' }; 
    }); 

    it('and then call the success action with the data returned by the API', result => { 
     expect(result).toEqual(put(actions.loginSuccess({ username: 'Ludo', email: '[email protected]' }))); 
    }); 
}); 

Thêm ví dụ (sử dụng Jest, Mocha và AVA) trên GitHub.

Các vấn đề liên quan