日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

go定时器 每天重复_通过测试学习Go:Hello, World

發(fā)布時間:2023/11/27 生活经验 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 go定时器 每天重复_通过测试学习Go:Hello, World 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

點擊上方藍色“Go語言中文網(wǎng)”關(guān)注我們,設(shè)個星標,每天學(xué)習(xí)?Go?語言

你可以在這里查看本章的所有代碼[1]

按照傳統(tǒng),我們學(xué)習(xí)新語言編寫的第一個程序都是 Hello,world。

在之前的章節(jié)[2]中,我們討論了 Go 死板的文件存放位置。

按照以下路徑創(chuàng)建目錄?$GOPATH/src/github.com/{your-user-id}/hello

如果你使用的是基于 Unix 的系統(tǒng),你的名字是「bob」并且很樂于遵循 Go 關(guān)于?$GOPATH?的約定(這是最簡單的設(shè)置方式)。那么你可以執(zhí)行以下命令?mkdir -p $GOPATH/src/github.com/bob/hello?快速創(chuàng)建目錄。

在該目錄下創(chuàng)建一個?hello.go?的文件并寫入以下代碼,鍵入?go run hello.go?來運行程序。

package main

import "fmt"

func main() {
fmt.Println("Hello, world")
}

它是如何運行的

當你使用 Go 編寫程序時,你將定義一個?main?包,并在其中定義一個?main?函數(shù)。包是一種將相關(guān)的 Go 代碼組合到一起的方式。

func?關(guān)鍵字通過一個名稱和函數(shù)體來定義函數(shù)。

通過?import "fmt"?導(dǎo)入一個包含?Println?函數(shù)的包,我們用它來打印輸出。

如何測試

你會如何測試這個程序?將你「領(lǐng)域」內(nèi)的代碼和外部世界(會引起副作用)分離開會更好。fmt.Println?會產(chǎn)生副作用(打印到標準輸出),我們發(fā)送的字符串在自己的領(lǐng)域內(nèi)。[^注1]

[^注1]: 原文: How do you test this? It is good to separate your "domain" code from the outside world (side-effects). The?fmt.Println?is a side effect (printing to stdout) and the string we send in is our domain.

所以為了更容易測試,我們把這些問題拆分開。

package main

import "fmt"

func Hello() string {
return "Hello, world"
}

func main() {
fmt.Println(Hello())
}

我們再次使用?func?創(chuàng)建了一個新函數(shù),但是這次我們在定義中添加了另一個關(guān)鍵字?string。這意味著這個函數(shù)返回一個字符串。

現(xiàn)在創(chuàng)建一個名為?hello_test.go?的新文件,我們將在這里為?Hello?函數(shù)編寫一個測試

package main

import "testing"

func TestHello(t *testing.T) {
got := Hello()
want := "Hello, world"

if got != want {
t.Errorf("got '%s' want '%s'", got, want)
}
}

在解釋之前,讓我們先運行一下代碼。在終端運行?go test,它應(yīng)該已經(jīng)通過了!為了檢驗測試,可以嘗試通過改變?want?字符串來破壞測試。

注意,你不必在多個測試框架之間進行選擇,然后理解如何安裝它們。你需要的一切都內(nèi)建在語言中,語法與你將要編寫的其余代碼相同。

編寫測試

編寫測試和寫函數(shù)很類似,其中有一些規(guī)則

  • 程序需要在一個名為?xxx_test.go?的文件中編寫

  • 測試函數(shù)的命名必須以單詞?Test?開始

  • 測試函數(shù)只接受一個參數(shù)?t *testing.T

現(xiàn)在這些信息足以讓我們明白,類型為?*testing.T?的變量?t?是你在測試框架中的 "hook"(鉤子),所以當你想讓測試失敗時可以執(zhí)行?t.Fail()?之類的操作。

我們再討論一些新的話題:

if

Go 的?if?語句非常類似于其他編程語言。

聲明變量

我們使用?varName := value?的語法聲明變量,它允許我們在測試中重用一些值使代碼更具可讀性。

t.Errorf

我們調(diào)用?t?的?Errorf?方法打印一條消息并使測試失敗。f?表示格式化,它允許我們構(gòu)建一個字符串,并將值插入占位符值?%s?中。當你測試失敗時,它能夠讓你清楚測試是如何運行的。

稍后我們將探討方法和函數(shù)之間的區(qū)別。

Go 文檔

Go 的另一個高質(zhì)量特征是文檔。通過運行?godoc -http :8000,可以在本地啟動文檔。如果你訪問?localhost:8000/pkg[3],將看到系統(tǒng)上安裝的所有包。

大多數(shù)標準庫都有優(yōu)秀的文檔和示例。瀏覽?http://localhost:8000/pkg/testing/[4]?是非常值得的,去看一下你有什么可以用的。

Hello, YOU

現(xiàn)在有了測試,就可以安全地迭代我們的軟件了。

在上一個示例中,我們在寫好代碼?之后?編寫了測試,以便你學(xué)會如何編寫測試和聲明函數(shù)。從此刻起,我們將?首先編寫測試

我們的下一個需求是讓我們指定問候的接受者。

讓我們從在測試中捕獲這些需求開始。這是基本的測試驅(qū)動開發(fā),可以確保我們的測試用例?確實?是測試我們想要的。當你回顧編寫測試時,存在一個風(fēng)險:即使代碼沒有按照預(yù)期工作,測試也可能繼續(xù)通過。

package main

import "testing"

func TestHello(t *testing.T) {
got := Hello("Chris")
want := "Hello, Chris"

if got != want {
t.Errorf("got '%s' want '%s'", got, want)
}
}

這時運行?go test,你應(yīng)該會獲得一個編譯錯誤

./hello_test.go:6:18: too many arguments in call to Hello
have (string)
want ()

當使用像 Go 這樣的靜態(tài)類型語言時,聆聽編譯器?是很重要的。編譯器理解你的代碼應(yīng)該如何拼接到一起工作,所以你就不必關(guān)心這些了。

在這種情況下,編譯器告訴你需要怎么做才能繼續(xù)。我們必須修改函數(shù)?Hello?來接受一個參數(shù)。

修改?Hello?函數(shù)以接受字符串類型的參數(shù)

func Hello(name string) string {
return "Hello, world"
}

如果你嘗試再次運行測試,main.go?將無法編譯,因為你沒有傳遞參數(shù)。傳遞參數(shù) "world" 讓它通過。

func main() {
fmt.Println(Hello("world"))
}

現(xiàn)在,當你運行測試時,你應(yīng)該看到類似的內(nèi)容

hello_test.go:10: got 'Hello, world' want 'Hello, Chris''

我們最終得到了一個可編譯的程序,但是根據(jù)測試它并沒有達到我們的要求。

為了使測試通過,我們使用?name?參數(shù)并用?Hello,?字符串連接它,

func Hello(name string) string {
return "Hello, " + name
}

現(xiàn)在再運行測試就應(yīng)該通過了。通常作為 TDD 周期的一部分,我們該著手?重構(gòu)?了。

關(guān)于版本控制的一點說明

此時,如果你正在使用版本控制(你應(yīng)該這樣做!)我將按原樣?提交?代碼。因為我們擁有一個測試支持的可用軟件。

不過我不會推送到主分支上,因為我下一步計劃重構(gòu)。現(xiàn)在提交很合適,當重構(gòu)中陷入混亂時你總是可以回到可用版本。

這里沒有太多可重構(gòu)的,但我們可以介紹一下另一種語言特性?常量

常量

通常我們這樣定義一個常量

const helloPrefix = "Hello, "

現(xiàn)在我們可以重構(gòu)代碼

const helloPrefix = "Hello, "

func Hello(name string) string {
return helloPrefix + name
}

重構(gòu)之后,重新測試,以確保沒有破壞任何東西。

常量應(yīng)該可以提高應(yīng)用程序的性能,它避免了每次調(diào)用?Hello?時創(chuàng)建?"Hello, "?字符串實例。

顯然,對于這個例子來說,性能提升是微不足道的!但是創(chuàng)建常量的價值是可以快速理解值的含義,有時還可以幫助提高性能。

再次回到 Hello, world

下一個需求是當我們的函數(shù)用空字符串調(diào)用時,它默認為打印 "Hello, World" 而不是 "Hello, "

首先編寫一個新的失敗測試

func TestHello(t *testing.T) {

t.Run("saying hello to people", func(t *testing.T) {
got := Hello("Chris")
want := "Hello, Chris"

if got != want {
t.Errorf("got '%s' want '%s'", got, want)
}
})

t.Run("say hello world when an empty string is supplied", func(t *testing.T) {
got := Hello("")
want := "Hello, World"

if got != want {
t.Errorf("got '%s' want '%s'", got, want)
}
})

}

這里我們將介紹測試庫中的另一個工具 -- 子測試。有時,對一個「事情」進行分組測試,然后再對不同場景進行子測試非常有效。

這種方法的好處是,你可以建立在其他測試中也能夠使用的共享代碼。

當我們檢查信息是否符合預(yù)期時,會有重復(fù)的代碼。

重構(gòu)不?僅僅?是針對程序的代碼!

重要的是,你的測試?清楚地說明?了代碼需要做什么。

我們可以并且應(yīng)該重構(gòu)我們的測試。

func TestHello(t *testing.T) {

assertCorrectMessage := func(t *testing.T, got, want string) {
t.Helper()
if got != want {
t.Errorf("got '%s' want '%s'", got, want)
}
}

t.Run("saying hello to people", func(t *testing.T) {
got := Hello("Chris")
want := "Hello, Chris"
assertCorrectMessage(t, got, want)
})

t.Run("empty string defaults to 'world'", func(t *testing.T) {
got := Hello("")
want := "Hello, World"
assertCorrectMessage(t, got, want)
})

}

我們在這里做了什么?

我們將斷言重構(gòu)為函數(shù)。這減少了重復(fù)并且提高了測試的可讀性。在 Go 中,你可以在其他函數(shù)中聲明函數(shù)并將它們分配給變量。你可以像調(diào)用普通函數(shù)一樣調(diào)用它們。我們需要傳入?t *testing.T,這樣我們就可以在需要的時候令測試代碼失敗。

t.Helper()?需要告訴測試套件這個方法是輔助函數(shù)(helper)。通過這樣做,當測試失敗時所報告的行號將在函數(shù)調(diào)用中而不是在輔助函數(shù)內(nèi)部。這將幫助其他開發(fā)人員更容易地跟蹤問題。如果你仍然不理解,請注釋掉它,使測試失敗并觀察測試輸出。

現(xiàn)在我們有了一個寫得很好的失敗測試,讓我們使用?if?修復(fù)代碼。

const helloPrefix = "Hello, "

func Hello(name string) string {
if name == "" {
name = "World"
}
return helloPrefix + name
}

如果我們運行測試,應(yīng)該看到它滿足了新的要求,并且我們沒有意外地破壞其他功能。

回到版本控制

現(xiàn)在我們對代碼很滿意,我將修改之前的提交,所以我們只提交認為好的版本及其測試。

規(guī)律

讓我們再次回顧一下這個周期

  • 編寫一個測試

  • 讓編譯通過

  • 運行測試,查看失敗原因并檢查錯誤消息是很有意義的

  • 編寫足夠的代碼以使測試通過

  • 重構(gòu)

從表面上看,這可能看起來很乏味,但堅持反饋循環(huán)非常重要。

它不僅確保你有?相關(guān)的測試,還可以確保你通過重構(gòu)測試的安全性來?設(shè)計優(yōu)秀的軟件

查看測試失敗是一個重要的檢查手段,因為它還可以讓你看到錯誤信息。作為一名開發(fā)人員,如果測試失敗時不能清楚地說明問題所在,那么使用這個代碼庫可能會非常困難。

通過確保你的測試?快速?并建立你的工具,以便運行測試足夠簡單,你在編寫代碼時就可以進入流暢的狀態(tài)。

如果不寫測試,你提交的時候通過運行軟件來手動檢查你的代碼,這會打破你的流暢狀態(tài),而且你任何時候都無法將自己從這種狀態(tài)中拯救出來,尤其是從長遠來看。

繼續(xù)前進!更多需求

天吶,我們有更多的需求了。我們現(xiàn)在需要支持第二個參數(shù),指定問候的語言。如果一種我們不能識別的語言被傳進來,就默認為英語。

通過 TDD 輕松實現(xiàn)這一功能,我們是有信心的!

為使用西班牙語的用戶編寫測試,將其添加到現(xiàn)有的測試用例中。

    t.Run("in Spanish", func(t *testing.T) {
got := Hello("Elodie", "Spanish")
want := "Hola, Elodie"
assertCorrectMessage(t, got, want)
})

記住不要欺騙自己!先編寫測試。當你嘗試運行測試時,編譯器?應(yīng)該?會出錯,因為你用兩個參數(shù)而不是一個來調(diào)用?Hello

./hello_test.go:27:19: too many arguments in call to Hello
have (string, string)
want (string)

通過向?Hello?添加另一個字符串參數(shù)來修復(fù)編譯問題

func Hello(name string, language string) string {
if name == "" {
name = "World"
}
return helloPrefix + name
}

當你嘗試再次運行測試時,它會抱怨在其他測試和?main.go?中沒有傳遞足夠的參數(shù)給?Hello

./hello.go:15:19: not enough arguments in call to Hello
have (string)
want (string, string)

通過傳遞空字符串來修復(fù)它們。現(xiàn)在,除了我們的新場景外,你的所有測試都應(yīng)該編譯并通過

hello_test.go:29: got 'Hola, Elodie' want 'Hello, Elodie'

這里我們可以使用?if?檢查語言是否是「西班牙語」,如果是就修改信息

func Hello(name string, language string) string {
if name == "" {
name = "World"
}

if language == "Spanish" {
return "Hola, " + name
}

return helloPrefix + name
}

測試現(xiàn)在應(yīng)該通過了。

現(xiàn)在是?重構(gòu)?的時候了。你應(yīng)該在代碼中看出了一些問題,其中有一些重復(fù)的「魔術(shù)」字符串。自己嘗試重構(gòu)它,每次更改都要重新運行測試,以確保重構(gòu)不會破壞任何內(nèi)容。

const spanish = "Spanish"
const helloPrefix = "Hello, "
const spanishHelloPrefix = "Hola, "

func Hello(name string, language string) string {
if name == "" {
name = "World"
}

if language == spanish {
return spanishHelloPrefix + name
}

return helloPrefix + name
}

法語

  • 編寫一個測試,斷言如果你傳遞?"French"?你會得到?"Bonjour, "

  • 看到它失敗,檢查易讀的錯誤消息

  • 在代碼中進行最小的合理更改

你可能寫了一些看起來大致如此的東西

func Hello(name string, language string) string {
if name == "" {
name = "World"
}

if language == spanish {
return spanishHelloPrefix + name
}

if language == french {
return frenchHelloPrefix + name
}

return helloPrefix + name
}

switch

當你有很多?if?語句檢查一個特定的值時,通常使用?switch?語句來代替。如果我們希望稍后添加更多的語言支持,我們可以使用?switch?來重構(gòu)代碼,使代碼更易于閱讀和擴展。

func Hello(name string, language string) string {
if name == "" {
name = "World"
}

prefix := helloPrefix

switch language {
case french:
prefix = frenchHelloPrefix
case spanish:
prefix = spanishHelloPrefix
}

return prefix + name
}

編寫一個測試,添加用你選擇的語言寫的問候,你應(yīng)該可以看到擴展這個?神奇?的函數(shù)是多么簡單。

最后一次重構(gòu)?

你可能會抱怨說也許我們的函數(shù)正在變得很臃腫。對此最簡單的重構(gòu)是將一些功能提取到另一個函數(shù)中。

func Hello(name string, language string) string {
if name == "" {
name = "World"
}

return greetingPrefix(language) + name
}

func greetingPrefix(language string) (prefix string) {
switch language {
case french:
prefix = frenchHelloPrefix
case spanish:
prefix = spanishHelloPrefix
default:
prefix = englishPrefix
}
return
}

一些新的概念:

  • 在我們的函數(shù)簽名中,我們使用了?命名返回值(prefix string)。

  • 這將在你的函數(shù)中創(chuàng)建一個名為?prefix?的變量。

    • 你只需調(diào)用?return?而不是?return prefix?即可返回所設(shè)置的值。

    • 它將被分配「零」值。這取決于類型,例如?int?是 0,對于字符串它是?""

    • 這將顯示在 Go Doc 中,所以它使你的代碼更加清晰。

  • 如果沒有其他?case?語句匹配,將會執(zhí)行?default?分支。

  • 函數(shù)名稱以小寫字母開頭。在 Go 中,公共函數(shù)以大寫字母開始,私有函數(shù)以小寫字母開頭。我們不希望我們算法的內(nèi)部結(jié)構(gòu)暴露給外部,所以我們將這個功能私有化。

總結(jié)

誰會知道你可以從?Hello, world?中學(xué)到這么多東西呢?

現(xiàn)在你應(yīng)該以下內(nèi)容有了一定的理解:

Go 的一些語法

  • 編寫測試

  • 用參數(shù)和返回類型聲明函數(shù)

  • ifelseswitch

  • 聲明變量和常量

TDD 過程以及步驟的重要性

  • 編寫一個失敗的測試,并查看失敗信息,可以看到我們已經(jīng)為需求寫了一個?相關(guān)?的測試,并且看到它產(chǎn)生了一個?易于理解的失敗描述

  • 編寫最少量的代碼以使其通過,因此我們知道我們有可工作軟件

  • 然后?重構(gòu),支持我們測試的安全性,以確保我們擁有易于使用的精心制作的代碼

在我們的例子中,我們通過小巧易懂的步驟從?Hello()?到?Hello("name"),到?Hello("name", "french")

與「現(xiàn)實世界」的軟件相比,這當然是微不足道的,但原則依然通用。TDD 是一門需要通過開發(fā)去實踐的技能,通過將問題分解成更小的可測試的組件,你編寫軟件將會更加輕松。


作者:Chris James[5]譯者:Donng[6]校對:polaris1119[7],pityonline[8]

本文由?GCTT[9]?原創(chuàng)編譯,Go 中文網(wǎng)[10]?榮譽推出

推薦閱讀:

  • 通過測試學(xué)習(xí)Go:安裝 Go,搭建開發(fā)環(huán)境

  • 通過測試學(xué)習(xí) Go 語言

喜歡該系列的朋友,歡迎關(guān)注“Go語言中文網(wǎng)”:

參考資料

[1]

你可以在這里查看本章的所有代碼:?https://github.com/quii/learn-go-with-tests/tree/master/hello-world

[2]

章節(jié):?https://github.com/studygolang/learn-go-with-tests/blob/master/zh-CN/install-go.md#Go-環(huán)境

[3]

localhost:8000/pkg:?localhost:8000/pkg

[4]

http://localhost:8000/pkg/testing/:?http://localhost:8000/pkg/testing/

[5]

Chris James:?https://dev.to/quii

[6]

Donng:?https://github.com/Donng

[7]

polaris1119:?https://github.com/polaris1119

[8]

pityonline:?https://github.com/pityonline

[9]

GCTT:?https://github.com/studygolang/GCTT

[10]

Go 中文網(wǎng):?https://studygolang.com/

總結(jié)

以上是生活随笔為你收集整理的go定时器 每天重复_通过测试学习Go:Hello, World的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。