0

0

为了胜利早早退出!

心靈之曲

心靈之曲

发布时间:2024-12-14 11:09:24

|

462人浏览过

|

来源于dev.to

转载

为了胜利早早退出!

超简短摘要:当出现错误时退出程序可能是个好主意。使用 gobail 会让您的生活更轻松。

当你的 go 代码出现错误时,你通常会看到类似这样的内容:

err := myfunc()
if err != nil {
    return fmt.errorf("doing my thing: %w", err)
}

您会在这个示例中注意到一些事情:

  1. 您必须检查是否有错误
  2. 有一些文本可以帮助诊断错误
  3. 错误被包装,与文本一起传回

那么接下来会发生什么?好吧,这一切又发生了。您检查错误值,描述它,然后将其传回。然后一切又重新开始。

我们为什么要这样做?为什么要这么努力?

这一切都取决于您正在编写的软件。当你遇到错误时,你必须做出决定。这个错误会发生什么?

如果您正在编写一个响应请求的 http api,那么最终您将获得某种 http 处理程序,并将该错误转换为某种响应 - 也许是一个带有礼貌提醒格式的小 400正确请求或可能返回 500 以及有关应用程序运行状况的令人担忧的消息。或者,如果您正在编写某种 cli 工具,那么您可能会决定错误最终会一直传递回您的主函数。对于任何类型的程序,您可能会认为已经足够了 - 该程序应该结束,因为您无法做任何其他事情。

让我们看看最后一个选项。什么时候退出程序合适?我能想到的几个原因:

a.没有别的办法了,错误太严重了,一切都必须立即停止
b.终止程序没有任何后果(不需要清理,没有状态可以响应)
c.尽早停止是可取的,也许你有一个监视器可以干净地重新启动该过程

无论什么原因,你都需要考虑如何干净利落地退出。现在您可能尝试的第一件事是:

err := myfunc()
if err != nil {
    fmt.printf("doing my thing: %v", err)
    os.exit(1)
}

它看起来与我们原来的错误处理代码非常相似,但有一些重要的区别。第一个是显而易见的——那里有一个很棒的stop-right-g*****n-now声明。你的程序不会继续下去。第二点也许更重要。调用此示例的代码不必担心处理任何错误。没有需要测试的其他代码路径 - 我们可以相信调用代码没有要测试的 if 块,因为没有返回任何需要我们检查的内容。

测试你的出口

所以,当我建议你应该相信你的退出代码会起作用时,我可能有点热情。您可能应该检查新程序停止的原因是否正确。

尝试 1 - 运行你的程序

这感觉应该很容易。这里有一些需要考虑的事情 - 在最简单的情况下,您只需运行程序并触发错误条件。例如,让 cli 工具打开一个不存在的文件。对于一些简单的情况,您可以手动执行此操作。当测试数量增加时,您可能需要某种自动化来帮助您。

快速旁注 - 这可能是另一篇博客文章的主题,但我目前最喜欢的测试 cli 工具的方法是使用 godog 来编写测试。它可能有点复杂,但我发现它非常强大。以下是我如何使用layli和wait-for来处理它的一些很好的例子。

这种方法会让您走得很远,但有时可能很难创造条件来正确执行您想要确信的所有代码路径。

尝试 2 - 模拟出口

好的,现在我们将使用 go 语言的一些功能。我们实际上不必调用 os.exit - 我们可以调用看起来像它的东西。所以看看这个:

Codiga
Codiga

可自定义的静态代码分析检测工具

下载
type exitfunc func(code int)

var customexit exitfunc = os.exit

func myfunc() {
    err := someotherfunc()
    if err != nil {
        fmt.printf("doing my thing: %v", err)
        customexit(1)
    }
}

那么我们如何利用这一点进行测试呢?由于函数现在已转换为变量 (customexit),因此我们可以用我们想要执行的其他操作替换该值。就像这样...

package sameastheabovecode

func testomgitsallgonewrong(t *testing.t) {
    oldexit := customexit
    defer func() {
        // make sure we reset the exit so it can be used elsewhere
        customexit = oldexit
    }

    exitcalled := false
    exitcode := 0
    customexit = func(code int) {
        exitcalled = true
        exitcode = code
    }

    // set up the mocks so that someotherfunc returns an error

    myfunc()

    // assume that we're using the fantastic stretchr/testify library here
    assert.true(t, exitcalled)
    assert.equal(t, 1, exitcode)
}

这是一种对单元测试更加友好的方法。您可以检查使用的退出代码是否正确 - 并且您实际上调用了退出函数。

从表面上看,这看起来不错,但有一个大问题 - 如果您的测试通过,那么您的程序将继续并在您期望函数退出时执行该函数的其余部分。即使测试设置意味着其余的执行无效并导致测试出现问题(例如引起恐慌),它仍将继续。

删除代码以删除测试

嗯,这听起来有点极端!

我觉得我应该解释一下......通常在“管理良好”的公司中,您需要确保每一行代码都已被证明是有效的,然后才能放在客户面前。使用上述技术,您可能无法生成正确的覆盖率指标来证明您的能力良好。即使推理起来微不足道。
上面的所有示例都假设当我们收到错误时,我们必须检查它以决定做什么(报复性退出)。如果我们能够退出而无需检查是否存在错误,那不是很好吗?

让我们看看我们能做什么。

func checkexit(err error) {
   fmt.printf("doing my thing: %v", err)
   customexit(1)
}

func myfunc() {
    checkexit(someotherfunc())
}

看一下上面的例子。功能是相同的,但 myfunc 的实现现在更加简单 - 没有条件。我们可以在自己的测试中检查 checkexit 函数的实现,这意味着 myfunc() 中的任何新内容都可以更容易地验证。

戈贝尔介绍

创建了一个新的库 gobail,它可以让您确信如果出现错误,它将得到处理,而无需增加您自己的代码的复杂性。看起来像这样:

func myfunc() {
    gobail.run(someotherfunc()).orexit("with message")
    gobail.run(yetanotherfunc()).orexit("with message")
}

这个库已经过全面测试,并具有覆盖率指标,以证明这一点。您可以安全地使用它,而不必担心错误会被跳过。它还将处理具有 2 个返回值的函数,如下所示:

gobail.Return2(return2ValsAndError()).OrExitMsg("something went wrong: %v")

另请注意,您包含了导致所有问题的错误。

也可以发生恐慌而不是退出,在调用恐慌时打印堆栈跟踪和程序中的其他上下文信息。请查看文档以了解更多详细信息。

隔离依赖关系

当您使用 gobail 编写软件时,您会注意到在与外部库交互时大多数情况下都必须使用它。这具有您通常需要编写来处理所有错误情况的附加代码,可以将其包装在对 return 或 return2 的调用中,并假设我们将在必要时退出。

结论

有时需要退出程序而不是详细处理错误。 gobail 库已创建并经过验证,因此您不必担心证明这一点的细节。

如果您发现可以进行的改进或只是有建议,请在存储库上提出 pr 或问题,开发人员会尽快处理!

相关专题

更多
if什么意思
if什么意思

if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

737

2023.08.22

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

388

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

571

2023.08.10

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

388

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

571

2023.08.10

http500解决方法
http500解决方法

http500解决方法有检查服务器日志、检查代码错误、检查服务器配置、检查文件和目录权限、检查资源不足、更新软件版本、重启服务器或寻求专业帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

335

2023.11.09

http请求415错误怎么解决
http请求415错误怎么解决

解决方法:1、检查请求头中的Content-Type;2、检查请求体中的数据格式;3、使用适当的编码格式;4、使用适当的请求方法;5、检查服务器端的支持情况。更多http请求415错误怎么解决的相关内容,可以阅读下面的文章。

406

2023.11.14

HTTP 503错误解决方法
HTTP 503错误解决方法

HTTP 503错误表示服务器暂时无法处理请求。想了解更多http错误代码的相关内容,可以阅读本专题下面的文章。

1711

2024.03.12

Java 桌面应用开发(JavaFX 实战)
Java 桌面应用开发(JavaFX 实战)

本专题系统讲解 Java 在桌面应用开发领域的实战应用,重点围绕 JavaFX 框架,涵盖界面布局、控件使用、事件处理、FXML、样式美化(CSS)、多线程与UI响应优化,以及桌面应用的打包与发布。通过完整示例项目,帮助学习者掌握 使用 Java 构建现代化、跨平台桌面应用程序的核心能力。

36

2026.01.14

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Git 教程
Git 教程

共21课时 | 2.7万人学习

Git版本控制工具
Git版本控制工具

共8课时 | 1.5万人学习

Git中文开发手册
Git中文开发手册

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号