Asi*_*sik 8 f# unit-testing functional-programming
我有一个函数负责收集一堆配置并从所有这些部分中进行更大的配置.所以它基本上是:
let applyUpdate updateData currentState =
if not (someConditionAbout updateData) then
log (SomeError)
let this = getThis updateData currentState.Thingy
let that = getThat updateData currentState.Thingy
let andThat = createThatThing that this updateData
// blablablablablabla
{ currentState with
This = this
That = that
AndThat = andThat
// etc. }
Run Code Online (Sandbox Code Playgroud)
我现在有单元测试getThis,getThat,createThatThing,但不适合applyUpdate.我不想重新测试getThis正在做什么等等,我只是想测试特定于applyUpdate和存根的逻辑getThis.在面向对象的样式中,这些将通过依赖注入通过接口传递.在功能方面,我不确定如何继续:
// This is the function called by tests
let applyUpdateTestable getThisFn getThatFn createThatThingfn etc updateData currentState =
if not (someConditionAbout updateData) then
log (SomeError)
let this = getThisFn updateData currentState.Thingy
// etc
{ currentState with
This = this
// etc. }
// This is the function that is actually called by client code
let applyUpdate = applyUpdateTestable getThis getThat etc
Run Code Online (Sandbox Code Playgroud)
这似乎是Bastard Injection的功能等同物,但除此之外,我主要关心的是:
如何在函数式编程中处理这些问题?
你说:
在面向对象的样式中,这些将通过依赖注入通过接口传递.
在FP中使用相同的方法,但不是通过对象构造函数注入,而是"注入"作为函数的参数.
所以你和你一起走在正确的轨道上applyUpdateTestable,除了它也将被用作真实的代码,而不仅仅是可测试的代码.
例如,这是传入三个额外依赖项的函数:
module Core =
let applyUpdate getThisFn getThatFn createThatThingfn updateData currentState =
if not (someConditionAbout updateData) then
log (SomeError)
let this = getThisFn updateData currentState.Thingy
// etc
{ currentState with
This = this
// etc. }
Run Code Online (Sandbox Code Playgroud)
然后,在"生产"代码中,您注入了真正的依赖项:
module Production =
let applyUpdate updateData currentState =
Core.applyUpdate Real.getThis Real.getThat Real.createThatThingfn updateData currentState
Run Code Online (Sandbox Code Playgroud)
或者更简单地说,使用部分应用:
module Production =
let applyUpdate =
Core.applyUpdate Real.getThis Real.getThat Real.createThatThing
Run Code Online (Sandbox Code Playgroud)
在测试版本中,您将注入模拟或存根:
module Test =
let applyUpdate =
Core.applyUpdate Mock.getThis Mock.getThat Mock.createThatThing
Run Code Online (Sandbox Code Playgroud)
在上面的"生产"示例中,我静态地硬编码了Real函数的依赖关系,但是,或者,就像OO样式依赖注入一样,生产applyUpdate可以由一些顶级协调器创建,然后传递到需要它的函数中.
这回答了你的问题,我希望:
这种方法有更复杂的版本,例如"Reader"monad,但上面的代码是最简单的方法.
Mark Seemann在这个主题上有很多好的帖子,比如集成测试和SOLID:下一步是功能和端口和适配器.
| 归档时间: |
|
| 查看次数: |
358 次 |
| 最近记录: |