我的应用程序中的所有逻辑都存在于action creators(thunks)中。大多数动作创建者的逻辑并不复杂,由条件表达式组成,条件是存储中的值:如果存储中存在此值,则分派这些动作创建者,否则分派此动作。还有一些“聚合器”,它们是动作创建者,通常基于某些状态值的存在来分派其他几个动作创建者;和api包装器,它们使用状态中的参数有条件地调用api抽象thunk,然后处理响应。
关键是,他们中的大多数人使用getState函数来获取他们自己需要的一切,而不是将其作为参数接收。现在,这种方法对我很有用,而且非常简单,但是我很难测试它。到目前为止,我所有的测试都是按照这个建议编写的:https://github.com/reactjs/redux/issues/2179.基本上,在开始时,我使用一些其他操作设置了所需的状态,模拟读取调用,然后调度我打算测试的thunk,然后使用各种选择器。这将在一个测试中同时测试多个动作、减速器和选择器。我喜欢我的测试完全验证特定用例的事实,但是我不确定这是否真的是一个好的实践。我的主要问题是,一些thunks是不可测试的,因为他们派遣了其他5个动作创建者,我很困惑如何至少验证他们被调用,除了检查状态是否改变,这反过来又使promise链变得巨大,并测试相同的功能在多个测试中一遍又一遍。
我对整个测试都不熟悉,互联网上所有的例子都是待办事项列表或其他可笑的简单CRUD应用程序,这些都没有帮助。在使用大量条件逻辑的复杂应用程序中,如何使用依赖于多个状态节点的动作创建者进行redux测试?
简短回答:模仿它。=)
详细回答:我个人确实更喜欢在测试中使用尽可能多的真实代码(即,不使用双重测试)。但有时这并不值得,你不得不回过头来嘲笑。
在类似您描述的情况下,您可能希望/需要在测试中检查以下几件事情:
根据您想要测试的上述内容的组合,可能会使用不同的策略。例如,如果您的被测thunk依赖于sub thunk的结果,则不需要检查sub thunk是否已被调度:只需模拟sub thunk,以便它返回特定的数据,这些数据将以特定、合理的方式影响被测thunk的行为(请参阅下面代码段中的auth
mock了解详细信息)。
让我们考虑下面的例子来说明可能的嘲弄策略。假设您必须实现授权功能。假设您的服务器通过httpendpoint对用户进行授权,如果成功,则发送回授权令牌,稍后用于打开websocket连接。假设您以以下方式设计了该功能:
还有connect
thunk,它使用用户的登录名和密码发送auth
子thunk,然后通过http发送给定的凭证。当服务器响应auth
时,thunk将接收到的令牌存储在存储中(仅出于说明性原因)并解析。当
auth
解析时,connect
发送otherStuff
thunk,这将使用令牌执行其他操作。最后,connect
通过wsApi
打开套接字连接。
// ======= 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) => {
// ...
};
我们要做的是模拟两个thunk:
auth
和otherStuff
connect
高度依赖于auth
,因此我们将确保仅通过检查connect
行为调用auth
,这取决于我们传递给auth
的模拟行为。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();
});
});
});
如果您需要对给定代码段的任何评论,请随时询问。
我正在为一个web应用程序实现一个相当复杂的输入验证,它应该输入一个ID,并将调用其他几个系统,以便在持久化包含该ID的对象之前检查该ID是否有效。我想使用bean验证,但后来我发现自己专门创建了一个bean来允许这种验证发生。事实上,为了进行远程服务调用,我不仅需要向验证器提供ID,还需要提供一些上下文信息。 您认为bean-validation始终是正确的验证位置吗,即使它很复杂并且需要Bea
随着应用程序的增长,在 reducer 逻辑中开始出现一些常见的模式。你可能会发现一部分 reducer 逻辑对于不同类型的数据做着相同的工作,你想通过对每种数据类型复用相同的公共逻辑来减少重复的代码。或者,你可能想要在 store 中处理某个类型的数据的多个”实例“。然而,Redux store 采用全局结构的设计本身就是一种折衷:优点是易于追踪应用程序的整体状态,但是,也可能更难的”命中“那些
在本章中,我们将讨论Axure RP中使用的条件逻辑。 如果 - 然后 - 在Axure中 与任何其他编程工具一样,Axure也支持条件逻辑,以在原型中创建增强的交互。 一旦熟悉了如何提供交互,为交互提供条件逻辑就是下一个层次。 以下是条件逻辑的简单流程 - 如果,单击特定小部件/屏幕 然后,执行特定的操作/交互 否则,保持/更改小部件或屏幕的状态 为了更好地理解这一点,让我们从前面的例子中恢复流
综述 在多功能的动态web应用程序中测试业务逻辑漏洞需要用非常规手段来思考。如果应用认证机制原先以1、2、3的步骤依次执行的验证身份目的来开发,万一用户从步骤1直接跳到步骤3会发生什么?用更加简单的例子来说,在打开失败、权限拒绝或仅仅500的错误的情况下,应用程序是否依然能够提供访问权限? 可以举出许多例子,但是不变的思想是“跳出常规思维”。这种类型的漏洞无法被漏洞扫描工具探测到,依赖于渗透测试人
问题内容: 如何将条件逻辑应用于Pandas DataFrame。 请参见下面显示的DataFrame, 我的原始数据显示在“数据”列中,并且期望的输出显示在其旁边。如果“数据”中的数字小于2.5,则所需的输出为False。 我可以应用循环并重新构建DataFrame …但是那是“非Python的” 问题答案: 只需将列与该值进行比较:
我怎么能在最后运行一些逻辑,而不是收集。 我可以像 我如何在过滤后运行最后的逻辑。 谢谢,拉维