如何对从库导入的函数进行桩件和跟踪?
来源:stackoverflow
时间:2024-03-14 08:39:30 456浏览 收藏
欢迎各位小伙伴来到golang学习网,相聚于此都是缘哈哈哈!今天我给大家带来《如何对从库导入的函数进行桩件和跟踪?》,这篇文章主要讲到等等知识,如果你对Golang相关的知识非常感兴趣或者正在自学,都可以关注我,我会持续更新相关文章!当然,有什么建议也欢迎在评论留言提出!一起学习!
我是一名 javascript 和 python 开发人员。这是使用 jestjs 测试框架的单元测试代码片段:
index.ts
:
import dotenv from 'dotenv'; export class osenvfetcher { constructor() { const output = dotenv.config(); if (output.error) { console.log('error loading .env file'); process.exit(1); } } }
index.test.ts
:
import { osenvfetcher } from './'; import dotenv from 'dotenv'; describe('osenvfetcher', () => { aftereach(() => { jest.restoreallmocks(); }); it('should pass', () => { const moutput = { error: new error('parsed failure') }; jest.spyon(dotenv, 'config').mockreturnvalueonce(moutput); const errorlogspy = jest.spyon(console, 'log'); const exitstub = jest.spyon(process, 'exit').mockimplementation(); new osenvfetcher(); expect(dotenv.config).tobecalledtimes(1); expect(errorlogspy).tobecalledwith('error loading .env file'); expect(exitstub).tobecalledwith(1); }); });
单元测试的结果:
pass stackoverflow/todo/index.test.ts (11.08s) osenvfetcher ✓ should pass (32ms) console.log error loading .env file at customconsole.(node_modules/jest-environment-enzyme/node_modules/jest-mock/build/index.js:866:25) ----------|---------|----------|---------|---------|------------------- file | % stmts | % branch | % funcs | % lines | uncovered line #s ----------|---------|----------|---------|---------|------------------- all files | 100 | 50 | 100 | 100 | index.ts | 100 | 50 | 100 | 100 | 6 ----------|---------|----------|---------|---------|------------------- test suites: 1 passed, 1 total tests: 1 passed, 1 total snapshots: 0 total time: 12.467s
示例中的测试方法在使用 arrange、act、assert 模式的 js 项目中很常见。由于dotenv.config()
方法会执行一些文件系统i/o操作,因此它有一个副作用。所以我们将为它做一个存根或模拟。这样我们的单元测试就没有副作用,并且是在隔离的环境中进行测试。
这同样适用于python。我们可以使用unittest.mock模拟对象库来做同样的事情。我对这些单元测试方法非常满意。
现在,我转而去,尝试做同样的事情。代码在这里:
osenvfetcher.go
package util import ( "log" "os" "github.com/joho/godotenv" ) var godotenvload = godotenv.load type envfetcher interface { getenv(key string) string } type osenvfetcher struct {} func newosenvfetcher() *osenvfetcher { err := godotenvload() if err != nil { log.fatal("error loading .env file") } return &osenvfetcher{} } func (f *osenvfetcher) getenv(key string) string { return os.getenv(key) }
osenvfetcher_test.go
:
package util import ( "testing" "fmt" ) func testosenvfetcher(t *testing.t) { old := godotenvload defer func() { godotenvload = old }() godotenvload = func() error { return } osenvfetcher := newosenvfetcher() port := osenvfetcher.getenv("port") fmt.println(port) }
测试用例尚未完成。我不确定应该如何模拟、存根或间谍 godotenv.load
方法(相当于 dotenv.config()
)和 log.fatal
方法?我找到了这个模拟包-mock.但是godotenv包没有接口,它是由函数组成的。
我正在寻找一些方法,例如 jest.mock(modulename, factory, options) 和 jest.spyon(object, methodname)。或者,像 sinonjs 的存根和间谍。或者,像茉莉花的间谍。这些方法几乎可以覆盖任何测试场景。无论使用di还是直接导入模块。
我看到了一些方法,但它们都有自己的问题。
例如https://stackoverflow.com/a/41661462/6463558。
我需要存根十个有副作用的方法怎么办?我需要将一个包的这些方法分配给10个变量,并在运行测试之前将它们替换为测试用例中的模拟版本十次。它是不可扩展的。也许我可以创建一个 __mocks__
目录并将所有模拟版本对象放入其中。这样我就可以在所有测试文件中使用它们。
使用依赖注入更好。通过这种方式,我们可以将模拟对象传递给函数/方法。但有些场景是直接导入包并使用包的方法(第三个或内置标准库)。这也是我问题中的场景。我觉得这种场景是不可避免的,一定会出现在代码的某一层。
我可以使用 jestjs
轻松处理这种情况,例如
util.js
,
exports.resolveaddress = function(addr) { // ... const data = exports.parsejson(json); return data; } exports.parsejson = function(json) {}
main.js
:
// import util module directly rather than using dependency injection import util from './util'; function main() { return util.resolveaddress(); }
main.test.js
:
import util from './util'; const mJson = 'mocked json data'; jest.spyOn(util, 'parseJSON').mockReturnValueOnce(mJson) const actual = main() expect(actual).toBe('mocked json data');
我直接导入 util
模块并模拟 util.parsejson
方法及其返回值。我不确定 go 的包是否可以做到这一点。目前,这些问题是安排问题。
此外,我还需要检查方法是否确实被调用,以确保代码逻辑和分支是正确的。 (例如,使用 jestjs
的 .tobecalledwith()
方法)。这是断言问题。
提前致谢!
解决方案
这是我基于此answer的解决方案:
osenvfetcher.go
:
package util import ( "log" "os" "github.com/joho/godotenv" ) var godotenvload = godotenv.load var logfatal = log.fatal type envfetcher interface { getenv(key string) string } type osenvfetcher struct {} func newosenvfetcher() *osenvfetcher { err := godotenvload() if err != nil { logfatal("error loading .env file") } return &osenvfetcher{} } func (f *osenvfetcher) getenv(key string) string { return os.getenv(key) }
osenvfetcher_test.go
:
package util import ( "testing" "errors" ) func mockrestore(ogodotenvload func(...string) error, ologfatal func(v ...interface{})) { godotenvload = ogodotenvload logfatal = ologfatal } func testosenvfetcher(t *testing.t) { // arrange ogodotenvload := godotenvload ologfatal := logfatal defer mockrestore(ogodotenvload, ologfatal) var godotenvloadcalled = false godotenvload = func(...string) error { godotenvloadcalled = true return errors.new("parsed failure") } var logfatalcalled = false var logfatalcalledwith interface{} logfatal = func(v ...interface{}) { logfatalcalled = true logfatalcalledwith = v[0] } // act newosenvfetcher() // assert if !godotenvloadcalled { t.errorf("godotenv.load should be called") } if !logfatalcalled { t.errorf("log.fatal should be called") } if logfatalcalledwith != "error loading .env file" { t.errorf("log.fatal should be called with: %s", logfatalcalledwith) } }
测试覆盖范围的结果:
☁ util [master] ⚡ go test -v -coverprofile cover.out === RUN TestOsEnvFetcher --- PASS: TestOsEnvFetcher (0.00s) PASS coverage: 80.0% of statements
覆盖 html 记者:
以上就是本文的全部内容了,是否有顺利帮助你解决问题?若是能给你带来学习上的帮助,请大家多多支持golang学习网!更多关于Golang的相关知识,也可关注golang学习网公众号。
-
502 收藏
-
502 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
139 收藏
-
204 收藏
-
325 收藏
-
477 收藏
-
486 收藏
-
439 收藏
-
357 收藏
-
352 收藏
-
101 收藏
-
440 收藏
-
212 收藏
-
143 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 508次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 484次学习