Go 每日一库之 testify

2、Go自动化测试入门-testify 先获取testify包:go get GitHub.com/stretchr/testify 一个简单的示例 让我们先看看传统上如何在 Go 中编写测试。这将让我们对提高可读性的 testify 有所了解。 我先来写一个简单的 Go 程序,它有一个输出函数, Calculate() 。 package main import ( "fmt" ) // 计算并返回 x + 2. func Calculate(x int) (result int) { result = x + 2 阅读详情

简介

testify可以说是最流行的(从 GitHub star 数来看)Go 语言测试库了。testify提供了很多方便的函数帮助我们做assert和错误信息输出。使用标准库testing,我们需要自己编写各种条件判断,根据判断结果决定输出对应的信息。

testify核心有三部分内容:

  • assert:断言;

  • mock:测试替身;

  • suite:测试套件。

准备工作

本文代码使用 Go Modules。

创建目录并初始化:

$ mkdir -p testify && cd testify
$ go mod init github.com/darjun/go-daily-lib/testify

安装testify库:

$ go get -u github.com/stretchr/testify

assert

assert子库提供了便捷的断言函数,可以大大简化测试代码的编写。总的来说,它将之前需要判断 + 信息输出的模式:

if got != expected {
  t.Errorf("Xxx failed expect:%d got:%d", got, expected)
}

简化为一行断言代码:

assert.Equal(t, got, expected, "they should be equal")

结构更清晰,更可读。熟悉其他语言测试框架的开发者对assert的相关用法应该不会陌生。此外,assert中的函数会自动生成比较清晰的错误描述信息:

func TestEqual(t *testing.T) {
  var a = 100
  var b = 200
  assert.Equal(t, a, b, "")
}

使用testify编写测试代码与testing一样,测试文件为_test.go,测试函数为TestXxx。使用go test命令运行测试:

$ go test
--- FAIL: TestEqual (0.00s)
    assert_test.go:12:
                Error Trace:
                Error:          Not equal:
                                expected: 100
                                actual  : 200
                Test:           TestEqual
FAIL
exit status 1
FAIL    github.com/darjun/go-daily-lib/testify/assert   0.107s

我们看到信息更易读。

testify提供的assert类函数众多,每种函数都有两个版本,一个版本是函数名不带f的,一个版本是带f的,区别就在于带f的函数,我们需要指定至少两个参数,一个格式化字符串format,若干个参数args:

func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{})
func Equalf(t TestingT, expected, actual interface{}, msg string, args ...interface{})

实际上,在Equalf()函数内部调用了Equal():

func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
  if h, ok := t.(tHelper); ok {
    h.Helper()
  }
  return Equal(t, expected, actual, append([]interface{}{msg}, args...)...)
}

所以,我们只需要关注不带f的版本即可。

Contains

函数类型:

func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool

Contains断言s包含contains。其中s可以是字符串,数组/切片,map。相应地,contains为子串,数组/切片元素,map 的键。

DirExists

函数类型:

func DirExists(t TestingT, path string, msgAndArgs ...interface{}) bool

DirExists断言路径path是一个目录,如果path不存在或者是一个文件,断言失败。

ElementsMatch

函数类型:

func ElementsMatch(t TestingT, listA, listB interface{}, msgAndArgs ...interface{}) bool

ElementsMatch断言listA和listB包含相同的元素,忽略元素出现的顺序。listA/listB必须是数组或切片。如果有重复元素,重复元素出现的次数也必须相等。

Empty

函数类型:

func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool

Empty断言object是空,根据object中存储的实际类型,空的含义不同:

  • 指针:nil;

  • 整数:0;

  • 浮点数:0.0;

  • 字符串:空串"";

  • 布尔:false;

  • 切片或 channel:长度为 0。

EqualError

函数类型:

func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) bool

EqualError断言theError.Error()的返回值与errString相等。

EqualValues

函数类型:

func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool

EqualValues断言expected与actual相等,或者可以转换为相同的类型,并且相等。这个条件比Equal更宽,Equal()返回true则EqualValues()肯定也返回true,反之则不然。实现的核心是下面两个函数,使用了reflect.DeapEqual():

func ObjectsAreEqual(expected, actual interface{}) bool {
  if expected == nil || actual == nil {
    return expected == actual
  }

  exp, ok := expected.([]byte)
  if !ok {
    return reflect.DeepEqual(expected, actual)
  }

  act, ok := actual.([]byte)
  if !ok {
    return false
  }
  if exp == nil || act == nil {
    return exp == nil && act == nil
  }
  return bytes.Equal(exp, act)
}

func ObjectsAreEqualValues(expected, actual interface{}) bool {
    // 如果`ObjectsAreEqual`返回 true,直接返回
  if ObjectsAreEqual(expected, actual) {
    return true
  }

  actualType := reflect.TypeOf(actual)
  if actualType == nil {
    return false
  }
  expectedValue := reflect.ValueOf(expected)
  if expectedValue.IsValid() && expectedValue.Type().ConvertibleTo(actualType) {
    // 尝试类型转换
    return reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), actual)
  }

  return false
}

例如我基于int定义了一个新类型MyInt,它们的值都是 100,Equal()调用将返回 false,EqualValues()会返回 true:

type MyInt int

func TestEqual(t *testing.T) {
  var a = 100
  var b MyInt = 100
  assert.Equal(t, a, b, "")
  assert.EqualValues(t, a, b, "")
}

Error

函数类型:

func Error(t TestingT, err error, msgAndArgs ...interface{}) bool

Error断言err不为nil。

ErrorAs

函数类型:

func ErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{}) bool

ErrorAs断言err表示的 error 链中至少有一个和target匹配。这个函数是对标准库中errors.As的包装。

ErrorIs

函数类型:

func ErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool

ErrorIs断言err的 error 链中有target。

逆断言

上面的断言都是它们的逆断言,例如NotEqual/NotEqualValues等。

Assertions 对象

观察到上面的断言都是以TestingT为第一个参数,需要大量使用时比较麻烦。testify提供了一种方便的方式。先以*testing.T创建一个*Assertions对象,Assertions定义了前面所有的断言方法,只是不需要再传入TestingT参数了。

func TestEqual(t *testing.T) {
  assertions := assert.New(t)
  assertion.Equal(a, b, "")
  // ...
}

顺带提一句TestingT是一个接口,对*testing.T做了一个简单的包装:

type TestingT interface{
  Errorf(format string, args ...interface{})
}

require

require提供了和assert同样的接口,但是遇到错误时,require直接终止测试,而assert返回false。

mock

testify提供了对 Mock 的简单支持。Mock 简单来说就是构造一个仿对象,仿对象提供和原对象一样的接口,在测试中用仿对象来替换原对象。这样我们可以在原对象很难构造,特别是涉及外部资源(数据库,访问网络等)。例如,我们现在要编写一个从一个站点拉取用户列表信息的程序,拉取完成之后程序显示和分析。如果每次都去访问网络会带来极大的不确定性,甚至每次返回不同的列表,这就给测试带来了极大的困难。我们可以使用 Mock 技术。

package main

import (
  "encoding/json"
  "fmt"
  "io/ioutil"
  "net/http"
)

type User struct {
  Name string
  Age  int
}

type ICrawler interface {
  GetUserList() ([]*User, error)
}

type MyCrawler struct {
  url string
}

func (c *MyCrawler) GetUserList() ([]*User, error) {
  resp, err := http.Get(c.url)
  if err != nil {
    return nil, err
  }

  defer resp.Body.Close()
  data, err := ioutil.ReadAll(resp.Body)
  if err != nil {
    return nil, err
  }

  var userList []*User
  err = json.Unmarshal(data, &userList)
  if err != nil {
    return nil, err
  }

  return userList, nil
}

func GetAndPrintUsers(crawler ICrawler) {
  users, err := crawler.GetUserList()
  if err != nil {
    return
  }

  for _, u := range users {
    fmt.Println(u)
  }
}

Crawler.GetUserList()方法完成爬取和解析操作,返回用户列表。为了方便 Mock,GetAndPrintUsers()函数接受一个ICrawler接口。现在来定义我们的 Mock 对象,实现ICrawler接口:

package main

import (
  "github.com/stretchr/testify/mock"
  "testing"
)

type MockCrawler struct {
  mock.Mock
}

func (m *MockCrawler) GetUserList() ([]*User, error) {
  args := m.Called()
  return args.Get(0).([]*User), args.Error(1)
}

var (
  MockUsers []*User
)

func init() {
  MockUsers = append(MockUsers, &User{"dj", 18})
  MockUsers = append(MockUsers, &User{"zhangsan", 20})
}

func TestGetUserList(t *testing.T) {
  crawler := new(MockCrawler)
  crawler.On("GetUserList").Return(MockUsers, nil)

  GetAndPrintUsers(crawler)

  crawler.AssertExpectations(t)
}

实现GetUserList()方法时,需要调用Mock.Called()方法,传入参数(示例中无参数)。Called()会返回一个mock.Arguments对象,该对象中保存着返回的值。它提供了对基本类型和error的获取方法Int()/String()/Bool()/Error(),和通用的获取方法Get(),通用方法返回interface{},需要类型断言为具体类型,它们都接受一个表示索引的参数。

crawler.On("GetUserList").Return(MockUsers, nil)是 Mock 发挥魔法的地方,这里指示调用GetUserList()方法的返回值分别为MockUsers和nil,返回值在上面的GetUserList()方法中被Arguments.Get(0)和Arguments.Error(1)获取。

最后crawler.AssertExpectations(t)对 Mock 对象做断言。

运行:

$ go test
&{dj 18}
&{zhangsan 20}
PASS
ok      github.com/darjun/testify       0.258s

GetAndPrintUsers()函数功能正常执行,并且我们通过 Mock 提供的用户列表也能正确获取。

使用 Mock,我们可以精确断言某方法以特定参数的调用次数,Times(n int),它有两个便捷函数Once()/Twice()。下面我们要求函数Hello(n int)要以参数 1 调用 1次,参数 2 调用两次,参数 3 调用 3 次:

type IExample interface {
  Hello(n int) int
}

type Example struct {
}

func (e *Example) Hello(n int) int {
  fmt.Printf("Hello with %d\n", n)
  return n
}

func ExampleFunc(e IExample) {
  for n := 1; n <= 3; n++ {
    for i := 0; i <= n; i++ {
      e.Hello(n)
    }
  }
}

编写 Mock 对象:

type MockExample struct {
  mock.Mock
}

func (e *MockExample) Hello(n int) int {
  args := e.Mock.Called(n)
  return args.Int(0)
}

func TestExample(t *testing.T) {
  e := new(MockExample)

  e.On("Hello", 1).Return(1).Times(1)
  e.On("Hello", 2).Return(2).Times(2)
  e.On("Hello", 3).Return(3).Times(3)

  ExampleFunc(e)

  e.AssertExpectations(t)
}

运行:

$ go test
--- FAIL: TestExample (0.00s)
panic:
assert: mock: The method has been called over 1 times.
        Either do one more Mock.On("Hello").Return(...), or remove extra call.
        This call was unexpected:
                Hello(int)
                0: 1
        at: [equal_test.go:13 main.go:22] [recovered]

原来ExampleFunc()函数中<=应该是<导致多调用了一次,修改过来继续运行:

$ go test
PASS
ok      github.com/darjun/testify       0.236s

我们还可以设置以指定参数调用会导致 panic,测试程序的健壮性:

e.On("Hello", 100).Panic("out of range")

suite

testify提供了测试套件的功能(TestSuite),testify测试套件只是一个结构体,内嵌一个匿名的suite.Suite结构。测试套件中可以包含多个测试,它们可以共享状态,还可以定义钩子方法执行初始化和清理操作。钩子都是通过接口来定义的,实现了这些接口的测试套件结构在运行到指定节点时会调用对应的方法。

type SetupAllSuite interface {
  SetupSuite()
}

如果定义了SetupSuite()方法(即实现了SetupAllSuite接口),在套件中所有测试开始运行前调用这个方法。对应的是TearDownAllSuite:

type TearDownAllSuite interface {
  TearDownSuite()
}

如果定义了TearDonwSuite()方法(即实现了TearDownSuite接口),在套件中所有测试运行完成后调用这个方法。

type SetupTestSuite interface {
  SetupTest()
}

如果定义了SetupTest()方法(即实现了SetupTestSuite接口),在套件中每个测试执行前都会调用这个方法。对应的是TearDownTestSuite:

type TearDownTestSuite interface {
  TearDownTest()
}

如果定义了TearDownTest()方法(即实现了TearDownTest接口),在套件中每个测试执行后都会调用这个方法。

还有一对接口BeforeTest/AfterTest,它们分别在每个测试运行前/后调用,接受套件名和测试名作为参数。

我们来编写一个测试套件结构作为演示:

type MyTestSuit struct {
  suite.Suite
  testCount uint32
}

func (s *MyTestSuit) SetupSuite() {
  fmt.Println("SetupSuite")
}

func (s *MyTestSuit) TearDownSuite() {
  fmt.Println("TearDownSuite")
}

func (s *MyTestSuit) SetupTest() {
  fmt.Printf("SetupTest test count:%d\n", s.testCount)
}

func (s *MyTestSuit) TearDownTest() {
  s.testCount++
  fmt.Printf("TearDownTest test count:%d\n", s.testCount)
}

func (s *MyTestSuit) BeforeTest(suiteName, testName string) {
  fmt.Printf("BeforeTest suite:%s test:%s\n", suiteName, testName)
}

func (s *MyTestSuit) AfterTest(suiteName, testName string) {
  fmt.Printf("AfterTest suite:%s test:%s\n", suiteName, testName)
}

func (s *MyTestSuit) TestExample() {
  fmt.Println("TestExample")
}

这里只是简单在各个钩子函数中打印信息,统计执行完成的测试数量。由于要借助go test运行,所以需要编写一个TestXxx函数,在该函数中调用suite.Run()运行测试套件:

func TestExample(t *testing.T) {
  suite.Run(t, new(MyTestSuit))
}

suite.Run(t, new(MyTestSuit))会将运行MyTestSuit中所有名为TestXxx的方法。运行:

$ go test
SetupSuite
SetupTest test count:0
BeforeTest suite:MyTestSuit test:TestExample
TestExample
AfterTest suite:MyTestSuit test:TestExample
TearDownTest test count:1
TearDownSuite
PASS
ok      github.com/darjun/testify       0.375s

测试 HTTP 服务器

Go 标准库提供了一个httptest用于测试 HTTP 服务器。现在编写一个简单的 HTTP 服务器:

func index(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintln(w, "Hello World")
}

func greeting(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintf(w, "welcome, %s", r.URL.Query().Get("name"))
}

func main() {
  mux := http.NewServeMux()
  mux.HandleFunc("/", index)
  mux.HandleFunc("/greeting", greeting)

  server := &http.Server{
    Addr:    ":8080",
    Handler: mux,
  }

  if err := server.ListenAndServe(); err != nil {
    log.Fatal(err)
  }
}

很简单。httptest提供了一个ResponseRecorder类型,它实现了http.ResponseWriter接口,但是它只是记录写入的状态码和响应内容,不会发送响应给客户端。这样我们可以将该类型的对象传给处理器函数。然后构造服务器,传入该对象来驱动请求处理流程,最后测试该对象中记录的信息是否正确:

func TestIndex(t *testing.T) {
  recorder := httptest.NewRecorder()
  request, _ := http.NewRequest("GET", "/", nil)
  mux := http.NewServeMux()
  mux.HandleFunc("/", index)
  mux.HandleFunc("/greeting", greeting)

  mux.ServeHTTP(recorder, request)

  assert.Equal(t, recorder.Code, 200, "get index error")
  assert.Contains(t, recorder.Body.String(), "Hello World", "body error")
}

func TestGreeting(t *testing.T) {
  recorder := httptest.NewRecorder()
  request, _ := http.NewRequest("GET", "/greeting", nil)
  request.URL.RawQuery = "name=dj"
  mux := http.NewServeMux()
  mux.HandleFunc("/", index)
  mux.HandleFunc("/greeting", greeting)

  mux.ServeHTTP(recorder, request)

  assert.Equal(t, recorder.Code, 200, "greeting error")
  assert.Contains(t, recorder.Body.String(), "welcome, dj", "body error")
}

运行:

$ go test
PASS
ok      github.com/darjun/go-daily-lib/testify/httptest 0.093s

很简单,没有问题。

但是我们发现一个问题,上面的很多代码有重复,recorder/mux等对象的创建,处理器函数的注册。使用suite我们可以集中创建,省略这些重复的代码:

type MySuite struct {
  suite.Suite
  recorder *httptest.ResponseRecorder
  mux      *http.ServeMux
}

func (s *MySuite) SetupSuite() {
  s.recorder = httptest.NewRecorder()
  s.mux = http.NewServeMux()
  s.mux.HandleFunc("/", index)
  s.mux.HandleFunc("/greeting", greeting)
}

func (s *MySuite) TestIndex() {
  request, _ := http.NewRequest("GET", "/", nil)
  s.mux.ServeHTTP(s.recorder, request)

  s.Assert().Equal(s.recorder.Code, 200, "get index error")
  s.Assert().Contains(s.recorder.Body.String(), "Hello World", "body error")
}

func (s *MySuite) TestGreeting() {
  request, _ := http.NewRequest("GET", "/greeting", nil)
  request.URL.RawQuery = "name=dj"

  s.mux.ServeHTTP(s.recorder, request)

  s.Assert().Equal(s.recorder.Code, 200, "greeting error")
  s.Assert().Contains(s.recorder.Body.String(), "welcome, dj", "body error")
}

最后编写一个TestXxx驱动测试:

func TestHTTP(t *testing.T) {
  suite.Run(t, new(MySuite))
}

总结

testify扩展了testing标准库,断言库assert,测试替身mock和测试套件suite,让我们编写测试代码更容易!

大家如果发现好玩、好用的 Go 语言库,欢迎到 Go 每日一库 GitHub 上提交 issue😄

参考

  1. testify GitHub:github.com/stretchr/testify

  2. Go 每日一库 GitHub:https://github.com/darjun/go-daily-lib

我

我的博客:https://darjun.github.io

欢迎关注我的微信公众号【GoUpUp】,共同学习,一起进步~

59c4c124a1f623f6b331aa7a1150048f.png

Go panic处理:从错误兜底到系统性治理 panic是Go运行时触发的致命中断信号,本质并非业务异常而是程序安全执行失效的紧急制动机制。其原理依赖于goroutine独立的defer链与runtime调度约束,recover仅在defer中且注册早于panic时才生效。技术价值在于实现可定位(完整堆栈+goroutine ID)、可收敛(goroutine级隔离)、可治理(自动分类+指标监控)的错误响应体系。典型应用场景包括HTTP服务结构化降级、gRPC调用panic阻断、定时任务自动恢复及测试阶段主动验证。本文聚焦生产级panic治理,深度融合 阅读详情

相关推荐

Go-Testify-标准go测试包一个的神圣扩展

Testify - 标准go测试包一个的神圣扩展

Go:测试库testify简介

testify可以说是最流行的(从 GitHub star 数来看)Go 语言测试库了。testify提供了很多方便的函数帮助我们做assert和错误信息输出。使用标准库testing,我们需要自己编写各种条件判断,根据判断结果决定输出对应的信息。assert:断言;mock:测试替身;suite:测试套件。

GIS摆渡人 1222

Unity UI适配核心:Canvas Scaler模式解析与2023版避坑指南

UI适配是游戏与应用开发中的基础挑战,其核心在于确保界面元素在不同屏幕分辨率与设备上保持视觉一致与功能可用。原理上,系统通过坐标转换与缩放计算,将设计稿的布局映射到物理屏幕。技术价值在于提升用户体验的一致性与产品的跨平台兼容性。应用场景广泛覆盖手游、PC端应用及各类交互界面。本文聚焦Unity引擎中的Canvas Scaler组件,深入剖析其Scale With Screen Size等模式的工作原理,并结合锚点设置、安全区域处理等高频搜索热词,提供解决UI错位、拉伸及异形屏适配等常见问题的工程实践方案,帮

weixin_30920597的博客 623

go测试包testify就这么用

testify是一个功能比较全的go语言测试框架,同时支持了断言、mock、套件等功能。原生兼容go语言testing包,单看某个功能可能不是最好的,但是整体上来看,testify的综合实力非常强。

伤心的辣条 826

【电子电力】IEEE33节点系统参数及拓扑图visio

IEEE33节点系统是一种广泛用于电力系统分析和研究的标准配电网络。该系统具有典型的辐射结构,适用于负载流分析、分布式发电优化及电力系统的可靠性评估。本报告主要基于IEEE33节点系统的拓扑图,讨论其在电子电力系统中的应用。通过MATLAB仿真分析了节点的电压分布、功率损耗等关键参数,并验证了系统的稳定性和有效性。

2401_84610415的博客 1万+

图像超分辨率在医学影像中的应用:如何用深度学习提升CT/MRI图像质量

本文探讨了深度学习驱动的图像超分辨率技术在医学影像(如CT/MRI)质量提升中的应用。文章分析了医学图像超分辨率在提升诊断信息含量、平衡保真度与临床相关性方面的独特挑战,并详细介绍了如何针对3D体数据特点定制模型架构、设计病理感知损失函数,以及解决高质量配对数据稀缺的策略。通过实战案例,阐述了从数据模拟、模型训练到临床评估的完整流程,旨在为医学影像的清晰化与诊断精准化提供有效解决方案。

weixin_29063681的博客 523

Go Testify学习与使用

是一个强大的 Go 语言单元测试库,它提供了丰富的断言功能、mock 机制和测试套件管理工具,使得编写测试更加容易和规范。方法设置了预期的输入和输出。当测试中调用这个方法时,它返回的值将是我们事先定义的“Mocked Data”。库,可以模拟依赖关系中的方法或接口,帮助测试代码中的外部依赖(如数据库、API 调用等)。的断言模块简化了验证测试结果的过程,提供了许多常用的断言方法。模块,允许将多个相关的测试组织成一个测试套件,并提供了。是 Go 语言中一个常用的单元测试库,它为标准的。

GitHub个人仓库地址:https://github.com/feiyuluoye ; 个人塔罗牌占卜平台:http://118.126.82.12:8080/ ; 欢迎广大Coding友共同交流讨论。 1640

AR-HMM模型 自回归隐马尔可夫模型

AR-HMM模型 自回归隐马尔可夫模型 数据处理过程 输入的视频数据首先需要被裁剪以适合动物的大小,在这之后考虑到模型建立的目的为行为状态的分类,于是需要消除可能一帧里带有多个动作状态的行为成分,这个过程也就是对帧。对帧之后我们的为了适应模型训练还需要对每一帧的数据进行小波分解(类似傅里叶变换的信号重构),此时数据预处理阶段完成。 信号重构后的数据拥有的特征维度过多,因此需要应用主成分分析法(PCA)来选出对于分类结果贡献度最高的前十个分类特征。至此自回归隐马尔可夫模型的准备工作就完成了。 AR-HMM自

weixin_46263718的博客 2284

go每日新闻(2021-08-12)——如何正确的使用 sarama 包操作 Kafka?

每日一谚:Passing a pointer over a channel is idiomatic. go中文网每日资讯--2021-08-12 一、Go语言中文网 CGO:关于回调函数和指针的传递 Go 常见算法面试题篇(二):在 O(1) 时间内删除单链表结点 二、亚军进化史 Go技术日报(2021-08-11)——如何基于DDD构建微服务架构 三、k8s技术圈 一文搞定 Containerd 的使用 四、脑子进煎鱼了 翻译了一篇关于Go编译器的文章 五、Go招聘 聊聊unsafe..

韩亚军的博客 473

S32K系列之PDB框图详解及PDB触发ADC

可编程延迟模块PDB,PDB可提供从内部或外部触发或可编程间隔信号到ADC硬件触发输入的可控制延迟。 PDB可以选择提供脉冲输出,用作CMP块中的采样窗口。 S32K系列的PDB资源如下表: PDB功能框图 在下图中,以下字母表示的意义: N:PDB通道的总数 n:PDB通道号,范围从0到N-1 M:每个PDB通道的总可用预触发 m:预触发编号,范围从0到M-1 Y:脉冲输出的总数 y:脉冲数...

zz56z56的博客 1万+

WSL2网络配置全攻略:如何让Windows和Linux子系统互相访问端口(附防火墙设置)

本文深入解析WSL2的网络架构,并提供详细的端口互通配置指南。针对WSL2与Windows宿主机之间常见的网络访问问题,文章从原理出发,逐步讲解如何识别网络环境、配置Windows防火墙规则、调整服务监听地址,并介绍镜像网络模式等进阶优化方案,最终实现稳定可靠的双向端口访问。

sony5的博客 1148

go每日新闻(2021-10-10)——[译]更快的时间解析

每日一谚: interface: Hey variable, if you implement my methods then you’re my type. go中文网每日资讯--2021-10-10 一、Go语言中文网 Go语言爱好者周刊:第 115 期 Go:浮点数精度丢失问题详解 二、Go招聘 Go 每日一库之 testify 三、k8s技术圈 Promethues 应用监控的一些实践 四、Gopher指北 URL中的空格、加号究竟应该使用何种方式编码 五、奇伢云存储 图解网络|收.

韩亚军的博客 546

基于FME—三调篇—尖锐角及小缝隙处理

1 问题分析: 该功能实现在FME较为简单,相对ARCGIS模型构建器以及ARCGIS ENGINE,FME更适合无代码基础的人群。在三调内业数据处理要求中,尖锐角是不允许存在的。本文基于FME实现了对尖锐角的自动查询与消除以及自动处理在消除尖锐角过程中产生的缝隙,并进行了拓扑检查,实现自动化批量处理尖锐角的功能,提高工作效率。 2 总体思路: 2.1 实现功能分析: 1.找出小于指定角度的尖锐角...

qq_33315579的博客 9181

awesome-go-cn 实战指南:用这份中文 Go 项目大全做库选型与生态导航

[awesome-go-cn](https://link.gitcode.com/i/b54b02d15a89d1762cea4983699321ed) 是 awesome-go 的中文版镜像,按天与上游英文文档同步(文档记录的最近一次同步时间为 2026-01-30 07:26:33)。本篇以 [README.md](https://link.gitcode.com/i/b54b02d15a89

gitblog_00094的博客 782

YOLOv12改进策略【Neck】| CGA Fusion:内容引导的注意力融合模块,空间权重引导的多模态特征自适应融合

本文记录的是利用CGA Fusion 模块改进 YOLOv12 的多模态融合部分。(Content-Guided Attention Fusion)通过内容引导注意力生成空间权重,引导高低层特征的自适应融合。本文利用模块,通过内容引导注意力生成空间权重,自适应地融合两个模态的特征,在特征融合阶段实现跨模态语义对齐与噪声抑制,增强对不同模态互补特征的利用能力,从而提升模型在多模态场景下的检测鲁棒性与准确性。DEA-Net: Single image dehazing based on detail-enhan

Limiiiing的博客 434

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

golang每日十题第1期

类型参数[T any]放函数名后;约束写在。约束即接口,可包含:类型集合()、方法集、或混合。~int表示底层类型为 int 的所有类型(含comparable是预声明约束,要求类型可用==!(用于 map key、去重)。注意它不含展开,不能与普通类型并集。自定义约束:type Number interface { ~int | ~int64 | ~float64 }return r }Go 1.21 内建;提供IntegerFloatOrdered。不该用泛型的场景。

Lee_woxinyiran的博客 375

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

Russ Cox:这不是Go项目的标准布局 | Gopher Daily (2021.04.28) ʕ◔ϖ◔ʔ

每日一谚:Profile before you decide something is performance critical.Go技术生态Go web开发的当前状态 - https:/...

TonyBai 346

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

golang每日十题第2期

并发/channel】select 多路复用的随机性、default、超时与空 select 的语义和陷阱是什么?

Lee_woxinyiran的博客 181

Go 1.15RC1发布!| Gopher Daily (2020.07.25) ʕ◔ϖ◔ʔ

每日一谚:When we have more than one file in a package, it's convention to create a doc.go con...

TonyBai 519

Gogs 仓库的 AGENTS.md 工程协作规范全解读:从编码到提交的完整开发约定

> 说明:本文将基于 [AGENTS.md](https://link.gitcode.com/i/fb2155f0ff04431c172f815c1aa09086) 这份仓库级开发协作手册,结合 Gogs(自托管 Git 服务)当前仓库的实际源码、构建配置与测试代码,逐条解读其对 AI 开发助手与人类开发者提出的工作准则,包括核心协作原则、Go 与前端编码规范、本地化流程、可访问性要求、构建与代

gitblog_01005的博客 480

GitHub每日最火火火项目(10.19)

GitHub每日最火火火项目(10.19)

qq_37281548的博客 511

mcp-grafana测试策略:单元测试、集成测试与云测试全解析

想要构建稳定可靠的 Grafana MCP 服务器吗?mcp-grafana 项目提供了完整的三层测试策略,确保您的监控和可观测性工具链坚如磐石。作为连接 AI 助手与 Grafana 监控平台的桥梁,mcp-grafana 通过精心设计的测试体系保障了数据查询、告警管理和仪表板操作等核心功能的可靠性。 ## 📊 为什么测试策略如此重要? 在 AI 驱动的监控场景中,mcp-grafana

gitblog_00822的博客 559

Go语言条件控制:从语法规范到生产级防御性编程

条件语句是程序逻辑分支的基石,其本质是布尔表达式求值与控制流跳转的结合。在Go语言中,这一机制被高度简化——无括号、无隐式转换、无自动else补全,从而将逻辑严谨性完全交由开发者掌控。理解if/else链的执行顺序、短路求值的副作用、短变量声明的作用域边界,以及switch与if-else的性能与可维护性差异,是写出高可靠代码的前提。尤其在微服务与高并发场景下,nil检查顺序、边界条件遗漏、变量遮蔽、竞态条件等常见陷阱,往往成为线上panic与超时的根源。本文聚焦Go条件控制的底层原理与工程实践,融合错误优

weixin_34037173的博客 601

Noms 编码性能测试台 codec-perf-rig 深度解析:测量编码/解码与集合构建吞吐量

`codec-perf-rig` 是 Noms(The versioned, forkable, syncable database)仓库中用于测量**值编码(encoding)与解码(decoding)性能**的 Go 性能测试台,其全部代码与基准数据位于 [go/perf/codec-perf-rig/](https://link.gitcode.com/i/126fd71be6ceaf9b9

gitblog_01087的博客 450

三月七小助手 March7thAssistant 完整使用指南:把星穹铁道日常周常交给自动化

March7thAssistant(三月七小助手)是一款面向《崩坏:星穹铁道》的开源自动化工具。它用图像识别和模拟操作,替你完成清体力、每日实训、周常挑战等任务。重复的点击交给程序去做,你不用自己动手。如果你玩的是 PC 版或云游戏,又不想把时间耗在每日任务上,它可以一试。 下图是主界面、设置页和手机推送的实拍。 [![三月七小助手主界面、设置页与消息推送展示](https://raw.git

gitblog_01161的博客 192

PanSou SuSu 搜索插件设计解析:异步网盘搜索插件的架构、算法与工程实践

本篇技术指南以 PanSou 网盘搜索系统中 SuSu 插件的设计文档为骨架,结合 [susu.go](https://link.gitcode.com/i/1c7aef72efe4d719a3f015da7ae8d265) 源码与 [plugin.go](https://link.gitcode.com/i/e86863d4949c3216de137124676f58e5) 异步插件框架,系统讲

gitblog_00009的博客 949
上一篇: Go 每日一库之 testing
下一篇: Go 每日一库之 bitset
darjun
博客等级 码龄10年 109粉丝 82原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值