如何在私有范围内测试功能?
Posted
技术标签:
【中文标题】如何在私有范围内测试功能?【英文标题】:How to test function in private scope? 【发布时间】:2020-12-04 17:00:01 【问题描述】:当我尝试直接测试它时,我无法断言函数selectXHandler
。因为它是在私有范围内定义的。我无法模拟或监视此功能,因为您无法访问它
export const CheckboxWrapper = (
x,
y,
z,
a = [],
: CheckboxWrapperProps) =>
const State = useContext(Context);
const [state, dispatch] = State;
const Items = state;
const selectXHandler = () =>
const payload =
x,
a,
;
dispatch( type: action, payload );
;
if (y)
return (
<div className="mt5">
<Checkbox
checked=selectedItems[x] !== undefined
label=z
onChange=selectXHandler
/>
</div>
);
return null;
;
const selectXHandler = jest.fn();
await fireEvent.click(checkbox);
expect(checkbox).toBeChecked();
expect(selectXHandler).toHaveBeenCalledTimes(1);
我收到以下错误:
expect(jest.fn()).toHaveBeenCalledTimes(expected)
Expected number of calls: 1
Received number of calls: 0
【问题讨论】:
您应该测试面向公众的行为,而不是内部实现细节。例如。测试你的 UI 元素如何变化,而不是调用什么内部函数 我正在研究集成测试,检查功能是否被触发是其中的一部分。 @bsapaka 您可以改为模拟 redux 并检查它的调度是否已被调用以及使用什么参数。它也是你的组件“公共接口”,不像里面的一些私人功能。假设,您重命名了您的内部函数 - 应用程序可能因此而损坏吗?不。另一方面,如果您的组件开始调度操作“A”而不是“B”,它可能会破坏您的应用程序。所以用测试覆盖它是有意义的。 @contextq 无论是哪种测试,它都应该始终测试公共合约,而不是内部实现。您应该能够以满足正确行为的方式更改任何内部结构,并且测试应该仍然通过。 @skyboyer 我没有使用 redux,而是使用 usereducer 和 context 来创建类似的东西。你能用伪代码提出建议吗? 【参考方案1】:正如上面在 cmets 中所讨论的,测试一些内部结构是一个糟糕的举动。想象一下这是可能的,我们重命名了该内部函数或将其内联或拆分为两个。我们测试它的测试会失败吗?确实。我们的应用程序会被破坏吗?当然不是。
我们应该绑定到公共接口。对于组件公共接口是:
import
s(如输入值)
props(也是输入值)
渲染结果(输出值)
如果使用了上下文(也让我们将其视为输入值)
所以我看到了下一个方法:
-
对于一些输入道具
我们模拟点击复选框
并验证上下文中的
dispatch
是否已使用某些所需参数调用。
我不太了解 RTL,所以我的示例将是关于酶的。但我确信将其转换为适当的 RTL 选择器查询会很容易。
import Context from '../where/its/placed/someContext.js';
it('dispatch is called with A on checkbox is clicked', () =>
const dispatch = jest.fn();
const state = ; // or some initial state your test requires
const ourComponent = mount(<Content.Provider value= dispatch, state >
<CheckboxWrapper ...somePropsYouNeed /></Content.Provider>);
ourComponent.find(label: 'some-label').simulate('change');
expect(dispatch).toHaveBeenCalledWith( type: 'someType', payload: 'somePayload' );
expect(dispatch).toHaveBeenCalledTimes(1);
);
【讨论】:
测试一些内部结构很糟糕 - 不是,这取决于具体情况。这对功能组件不利,因为它们不是为此而设计的。我经常看到“测试行为而不是执行”被视为宗教教条,这是 IMO 的一个非常糟糕的举动。 我们测试它的测试会失败吗?确实。我们的应用程序会被破坏吗?当然不是 - 为什么这是一件坏事?比应用程序损坏时不会失败的测试好很多倍。如果你在修复不应该失败的测试上浪费了几个小时,那就太糟糕了。如果断言内部结构可以节省您数小时的调试时间,那很好。 YMMV @EstusFlask 工程总是关于妥协,同意你的看法。但是,如果初学者开发人员从一开始就将自己绑定到测试内部,他们最终会得到两个结果:不可靠的测试和由于脆弱性而浪费时间进行维护。还有一点“为什么这是一件坏事?” - 因为(当然,取决于情况)它使重构几乎不可能。很少有人喜欢痛苦,大多数人只是跳过重构,如果必须更新 10 多个测试以满足提升状态或移动方法到共享助手重构。 @EstusFlask 实际上我上面的示例也是一个折衷方案(我意识到这一点)并且部分依赖于内部结构(Context
如何工作的内部结构,针对dispatch
的论点的断言)。完全独立于内部的将是相当集成的,当我们在 Checkbox
上触发事件并验证 另一个 组件是否相应更改时,将呈现 <Provider><CheckboxWrapper /><AnotherComponentThatConsumesContext /></Provider>
。以上是关于如何在私有范围内测试功能?的主要内容,如果未能解决你的问题,请参考以下文章