2

我正在学习 cyclejs 和 rxjs,我正在努力为我正在开发的组件之一编写单元测试。我很抱歉这个长问题。我试图简化问题,这是我能做的最好的。

组件做以下事情:
1)当它被加载时,它向端点发送一个请求来检索用户的任务。从这些任务中,它找到用户当前正在处理的任务并创建一个包含端点的 url 流,当用户单击完成任务按钮时将调用该端点。
2)当一个新值进入测试流时,它会从迄今为止定义的测试中创建一个新流。
3)当用户点击完成任务时,组件首先向端点发送请求,将用户定义的测试添加到任务中。然后,如果调用成功,组件向端点发送另一个请求,该请求在步骤 1 中检索以完成任务。
4) 完成任务请求完成后,组件向用户显示通知。

这是组件:

import Rx from 'rx';
import {Observable} from 'rx';


const Model = ({test$, completeTask$, sources}) => {
    const processId = Number(sources.routeParams.processId);

    const SET_TEST_RESULTS = `http://dummyhost/tosettests/${processId}`;
    const GET_USER_TASKS = 'http://dummyhost/togetusertasks';

    const taskRequest$ = Observable.just({
        url: GET_USER_TASKS,
        method: 'GET'
    });

    const url$ = sources.HTTP
        .filter(response => response.request.url === GET_USER_TASKS)
        .flatMap(response => response.body)
        .filter(task => task.processId === processId)
        .take(1)
        .map(task=> {
            const activitiId = task.processInstanceId;
            return {
                completeTask: `http://dummyhost/tocompletetask/${activitiId}`
            };
        });

    const definedTest$ = test$
        .scan((acc, curr) => {
            acc.push(curr);
            return acc;
        }, [])
        .startWith([])
        .share();

    const setTestResultsRequest$ = completeTask$
        .withLatestFrom(definedTest$, (event, tests) => {
            return {
                url: SET_TEST_RESULTS,
                method: 'POST',
                send: {
                    tests
                }
            };
        });

    const setTestResultsResponse$ = sources.HTTP
        .filter(response => response.request.url === SET_TEST_RESULTS);

    const completeTaskRequest$ = setTestResultsResponse$
        .withLatestFrom(url$, (response, url) => {
            return {
                url: url.completeTask,
                method: 'POST'
            };
        });

    const completeTaskResponse$ = sources.HTTP
        .withLatestFrom(url$, (response, url) => {
            return {
                response,
                url
            };
        })
        .filter(data => data.response.request.url === data.url.completeTask)
        .map((data)=> data.response);

    const successNotification$ = completeTaskResponse$
        .map(() => {
            return {
                action: 'success',
                message: 'Tests have been defined!'
            };
        });


    const request$ = Observable.merge(taskRequest$, setTestResultsRequest$, completeTaskRequest$);

    return {
        request$: request$,
        notification$: successNotification$,
        definedTest$: definedTest$
    };
};

我要进行单元测试的内容如下:
1) 组件必须发送请求以定义任务的测试
2) 组件必须发送请求以完成任务
3) 组件必须显示通知

这是我到目前为止用 Mocha 编写的单元测试:

describe('When complete task is clicked', ()=> {
    const tests = [
        {
            name: 'test 1 name'
        },
        {
            name: 'test 2 name'
        },
        {
            name: 'test 3 name'
        }
    ];
    const test$ = Observable.fromArray(tests);
    const completeTask$ = Observable.just({}).delay(300);
    const processId = 3;
    const activitiId = 3;
    var actions;

    before(done => {
        const HTTPSource = new Rx.ReplaySubject();
        const sources = {
            DOM: mockDOMSource(),
            routeParams: {processId},
            HTTP: HTTPSource
        };

        actions = Model({test$, completeTask$, sources});
        const request$ = actions.request$.share();

        request$
            .filter(request=> request.url === 'http://dummyhost/togetusertasks')
            .subscribe((request) => {
                const response = {
                    request,
                    body: [{
                        processId,
                        processInstanceId: activitiId
                    }]
                };
                HTTPSource.onNext(response);
            });

        request$
            .filter(request=> request.url === `http://dummyhost/tosettests/${processId}`)
            .subscribe((request) => {
                const response = {
                    request
                };

                HTTPSource.onNext(response);
            });

        request$
            .filter(request=> request.url === `http://dummyhost/tocompletetask/${activitiId}`)
            .subscribe((request) => {
                const response = {
                    request
                };

                HTTPSource.onNext(response);
                done();
            });


    });

    it('should send a request to add tests', (done)=> {
        actions.request$
            .filter(request=> request.url === `http://dummyhost/tosettests/${processId}`)
            .subscribe(() => {
                done();
            });
    });

    it('should send a request to complete task', (done)=> {
        actions.request$
            .filter(request=> request.url === `http://dummyhost/tocompletetask/${activitiId}`)
            .subscribe(() => {
                done();
            });
    });

    it('should show a notification to inform user that tests have been defined', (done) => {
        actions.notification$.take(1)
            .subscribe(notification => {
                expect(notification.action).to.equal('success');
                done();
            });
    });
});

在测试中,我尝试模拟 HTTP 源。通过订阅从组件返回的请求流接收器,我可以为每个请求创建模拟响应。但是我必须使用共享运算符才能成功运行mocha 的 before 功能。否则,我只能模拟第一个正在检索用户任务的请求。所以,我的第一个问题是:

为什么我必须使用共享运算符才能成功运行 mocha 的 before 功能?

目前,发送验证完整任务请求的测试并显示通知通过。但是,验证对任务请求的定义测试的测试失败。这很奇怪,因为要验证发送了完整的任务请求,组件必须首先向任务请求发送定义测试。似乎在从组件接收器返回的请求流中以某种方式丢失了任务请求的定义测试。所以我的第二个问题是:
为什么第二次和第三次测试通过但第一次测试失败?

这是一个包含所有代码在一个文件中的要点: 要点链接

正如我之前所说,我是 cyclejs 和 rxjs 的新手。我想我没有完全理解我在测试什么。因此,欢迎任何关于 cyclejs 和 rxjs 的评论或答案,这些评论或答案为我指明了正确的道路。

如果您认为问题不够清楚,请告诉我。我会尽力改进这个问题。

4

0 回答 0