20201017のGoに関する記事は7件です。

AtCoder Beginner Contest 180のメモ

前置き

Atcoderをやってみたので、自分用のメモです。
あとから加筆・修正する予定です。

問題

https://atcoder.jp/contests/abc180

A

Q_A.go
package main

import (
    "fmt"
)

func main() {
    var n, a, b int
    fmt.Scanf("%d %d %d", &n,&a,&b)

    fmt.Printf("%d\n", n-a+b)
}

B

Q_B.go
package main

import (
    "fmt"
    "math"
)

func main() {
    var n int
    fmt.Scanf("%d", &n)

    var t int
    manhattan :=0
    euqulid :=0
    chebishev :=0

    for i := 0; i < n; i++ {
        fmt.Scanf("%d", &t)

        if t > 0 {
            manhattan += t
        }else{
            manhattan -= t
        }

        euqulid += t*t

        if t > 0 {
            if t > chebishev{
                chebishev = t
            }
        }else{
            if -t > chebishev{
                chebishev = -t              
            }  
        }
    }

    fmt.Printf("%d\n", manhattan)

    fmt.Printf("%.10f\n", math.Sqrt(float64(euqulid)))

    fmt.Printf("%d\n", chebishev)

}

C

Q_C.go
package main

import (
    "fmt"
)

func main() {
    var n int
    fmt.Scanf("%d", &n)

    max := make([]int, 1)

    for i:=1; i*i<n+1; i++{
        if n % i == 0{
            if n/i != i{
                max = append(max, n/i)
            }
            fmt.Printf("%d\n", i)
        }
    }


    for i:=len(max)-1; i>0; i--{
        if max[i] != 0{
            fmt.Printf("%d\n", max[i])
        }
    }
}

D

Q_D.go
package main

import (
    "fmt"
)

func main() {
    var x, y, a, b uint64
    fmt.Scanf("%d %d %d %d", &x, &y, &a, &b)

    var cnt uint64 = 0

    for x < y/a & b/(a-1) {
        cnt++
        x *= a
    }

    cnt += (y-1-x)/b

    fmt.Printf("%d\n", cnt)
}

E

覚えてたら後で書きます。

F

覚えてたら後で書きます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AtCoder Beginner Contest 180 参戦記

AtCoder Beginner Contest 180 参戦記

ABC180A - box

1分で突破. 書くだけ.

N, A, B = map(int, input().split())

print(N - A + B)

ABC180B - Various distances

3分で突破. 書くだけ.

N, *x = map(int, open(0).read().split())

print(sum(abs(a) for a in x))
print(sum(a * a for a in x) ** 0.5)
print(max(abs(a) for a in x))

ABC180C - Cream puff

3分で突破. 書くだけ. Nの二乗根まで回すと分かっていれば難しいことはないんじゃないかな.

N = int(input())

result = set()
for i in range(1, int(N ** 0.5) + 1):
    if N % i == 0:
        result.add(i)
        result.add(N // i)
print(*sorted(result), sep='\n')

ABC180D - Takahashi Unevolved

14分で突破. 時間かかりすぎ. 素直にシミュレートするナイーブなコードだと B が小さい場合に TLE になることは火を見るよりも明らか. となると、+ B より * A のほうが増分が小さいうちは * A をして、残りはまとめて足せば良いんじゃないのという結論に落ち着く. A は少なくとも2なので、素直にシミュレートしても O(logN) なので問題ない.

X, Y, A, B = map(int, input().split())

result = 0
while X * A < Y and X * A < X + B:
    X *= A
    result += 1
result += ((Y - 1) - X) // B
print(result)

追記: どうにもD問題でペナ食らった人が多いなあと思っていたが、工夫せずに書くと X * A が int64 でもオーバーフローするせいなのね. なるほど.

package main

import (
    "bufio"
    "fmt"
    "os"
    "strconv"
)

func main() {
    defer flush()

    X := readInt()
    Y := readInt()
    A := readInt()
    B := readInt()

    result := 0
    for X <= (Y-1)/A && X*A < X+B {
        X *= A
        result++
    }
    result += ((Y - 1) - X) / B
    println(result)
}

const (
    ioBufferSize = 1 * 1024 * 1024 // 1 MB
)

var stdinScanner = func() *bufio.Scanner {
    result := bufio.NewScanner(os.Stdin)
    result.Buffer(make([]byte, ioBufferSize), ioBufferSize)
    result.Split(bufio.ScanWords)
    return result
}()

func readString() string {
    stdinScanner.Scan()
    return stdinScanner.Text()
}

func readInt() int {
    result, err := strconv.Atoi(readString())
    if err != nil {
        panic(err)
    }
    return result
}

var stdoutWriter = bufio.NewWriter(os.Stdout)

func flush() {
    stdoutWriter.Flush()
}

func println(args ...interface{}) (int, error) {
    return fmt.Fprintln(stdoutWriter, args...)
}

ABC180E - Traveling Salesman among Aerial Cities

39分半で突破. 蟻本のコードを写経して解いた. 写経してあれば黄色パフォとか取れたかな、くそー.

#include <bits/stdc++.h>
#define rep(i, a) for (int i = (int)0; i < (int)a; ++i)
using ll = long long;
using namespace std;

#define MAX_N 17
#define INF 2147483647

ll N;
ll dp[1 << MAX_N][MAX_N];
ll d[MAX_N][MAX_N];

void solve() {
    rep(i, 1 << N) rep(j, N) dp[i][j] = INF;
    dp[(1 << N) - 1][0] = 0;

    for (int S = (1 << N) - 2; S >= 0; S--) {
        for (int v = 0; v < N; v++) {
            for (int u = 0; u < N; u++) {
                dp[S][v] = min(dp[S][v], dp[S | 1 << u][u] + d[v][u]);
            }
        }
    }
    cout << dp[0][0] << endl;
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);

    cin >> N;

    vector<ll> X(N), Y(N), Z(N);
    rep(i, N) {
        cin >> X[i] >> Y[i] >> Z[i];
    }

    rep(i, N) {
        rep(j, N) {
            d[i][j] = abs(X[i] - X[j]) + abs(Y[i] - Y[j]) + max(0ll, Z[i] - Z[j]);
        }
    }

    solve();

    return 0;
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GoでローカルWebServerを立てた

初めに

GoでWebServerを立てて、Androidアプリからアクセスする

環境

PC Windows10
Android Studio 4.0
Kotlin 1.3.72
Android端末 Emulator(API Level 29)
Go 1.11.1

構成図

go_server.png
Androidアプリからファイルを送信して、サーバー側で保存、サーバーからアプリにステータスコードを返却する

実装

ローカルサーバー

Server.go
package controllers

import (
    "fmt"
    "net/http"
    "io/ioutil"
    "os"
)

func apiSampleHandler(w http.ResponseWriter, r *http.Request) {
    switch(r.Method) {
        case "POST":
            fmt.Println("POST")
            // アップロードしたファイルとヘッダーを取得 
            file, fileHeader, _ := r.FormFile ("upload_file") 
            fileName := fileHeader.Filename // ヘッダーからファイル名を取得
            defer file.Close()              // ファイルを最後にClose
            data, _ := ioutil.ReadAll(file) // ファイルを読み出し
            saveFile, _ := os.Create(fileName) // 保存用のファイルを生成
            defer saveFile.Close()          // 保存用のファイルを最後にClose
            _, err = saveFile.Write(data)   // ファイルに書き込み
            if err != nil {
                fmt.Println("can not write file")
                w.WriteHeader(http.StatusBadRequest)
                return
            }
        case "GET":
            fmt.Println("GET")
    }
    // 200:OKを返す 
    w.WriteHeader(http.StatusOK)
}

// main.goから呼び出してサーバーを起動
func StartWebServer() error {
    http.HandleFunc("/", apiSampleHandler)
    return http.ListenAndServe(":8080", nil)
}

main.goを実行し、サーバーを起動
http://localhost:8080 にアクセスして、サーバーが起動していることを確認

Android アプリ

1.Androidmanifest.xml

インターネットにアクセスするためのPermissionを定義

AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" />

Android 9.0からhttpの通信の設定がOFFになるのでusesCleartextTraficをtrueに設定

AndroidManifest.xml
<application
     省略
    android:usesCleartextTraffic="true">
    <activity android:name=".MainActivity">
        省略
    </activity>
</application>

2.ファイルを生成

Android端末のアプリ固有領域(/data/data/{package_name}/files配下)にテキストファイルを生成

File.kt
const val FILE_EXPAND = ".txt"

class File {
    fun makeTxtFile(context: Context, fileName: String, str: String) {
        try {
            context.openFileOutput(fileName + FILE_EXPAND, Context.MODE_PRIVATE).use {
                it.write(str.toByteArray())
            }
        } catch (e: IOException) {
            Log.e("File", "#makeTxtFile $e")
        }
    }
}

ファイルの生成を確認
Device File Explorer でデバイス上のファイルを表示する

3.サーバーアクセス

ファイルを読み込んで、http通信でファイルを送信する

Net.kt
 fun startConnection(context: Context, requestUrl: String, requestMethod: String, fileName: String): Pair<Int, String> {
        val url = URL(requestUrl)                      // URLオブジェクト生成
        // UrlConnectionオブジェクト生成
        val urlConnection = url.openConnection() as HttpURLConnection 
        var result = ""
        var responseCode = 0
        try {
            val boundary = "--------------------------" 
            urlConnection.requestMethod = requestMethod // POST, GETなど
            urlConnection.doOutput = true               // リクエストボディの送信
            urlConnection.doInput = true                // レスポンスボディの受信
            urlConnection.useCaches = false             // キャッシュの利用
            // multipart/form-data:複数のデータを送信、boundary:複数データ間の区切り
            urlConnection.setRequestProperty(
                "Content-Type",
                "multipart/form-data; boundary=$boundary" 
            )
            val filePath = context.filesDir             // アプリ固有領域のパス
            val file = File("$filePath/$fileName$FILE_EXPAND") // ファイルオブジェクトを生成
            FileInputStream(file).use { fileInputStream ->
                urlConnection.connect()                 // コネクションを確立
                DataOutputStream(urlConnection.outputStream).use {
                   it.writeBytes(                       // headerを設定
                       TWO_HYPHEN + boundary + LINE_END +
                               "Content-Disposition: form-data; name=\"upload_file\"; " +
                               "filename=\"$fileName$FILE_EXPAND\"$LINE_END" +
                               "Content-Type: application/octet-stream$LINE_END$LINE_END"
                   )
                   // ファイル書き込み
                   val buffer = ByteArray(BUFFER_SIZE)
                   var bytesRead: Int
                   do {
                       bytesRead = fileInputStream.read(buffer)
                       if (bytesRead == -1) break
                       it.write(buffer, 0, bytesRead)
                   } while (true)
                   it.writeBytes(                       // footerの設定
                        LINE_END + TWO_HYPHEN + boundary + TWO_HYPHEN + LINE_END
                   )
                   it.flush()
                }
            }
            responseCode = urlConnection.responseCode   // レスポンスコードを取得

            BufferedReader(InputStreamReader(urlConnection.inputStream)).use {
                val sb = StringBuffer()
                for (line in it.readLines()) {
                    line.let { sb.append(line) }
                }
                result = sb.toString()
            }
        } catch (e: Exception) {
            Log.e("Net", "#startConnection$e")
        } finally {
            urlConnection.disconnect()
        }
        return responseCode to result
    }
}

4.IPアドレスの確認

アクセスしたいサーバー(PC)のIPアドレスをcommand promptで以下を実行し確認

>ipconfig

5.PCとAndroid端末を同一のネットワーク環境に接続

6.Androidにて接続

Net#startConnectionのrequestUrlにhttp://{確認したIPアドレス}:8080を設定してアプリを実行

ファイルのアップロードを確認

PCにてmain.goと同じディレクトリを確認する
ファイルが作成されていれば完了

最後に

全体ソースはこちら
アクセス先やRequestMethod、ファイル名はアプリで動的に変更できるようにしています。

参考文献

Goサーバー側

Go言語でのファイルアップロード

Androidアプリ側

[Android] アプリ内にファイルを保存する FileOutputStream, FileInputStream
Upload File To Server - Android Example
[Android]kotlinでのwhile-FileInputStream.readエラー
【Kotlin】複数の値を返したい!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GoでローカルWebServerを立てた~ファイルアップロード~

初めに

GoでWebServerを立てて、Androidアプリからファイルのアップロードを行う

環境

PC Windows10
Android Studio 4.0
Kotlin 1.3.72
Android端末 Emulator(API Level 29)
Go 1.11.1

構成図

go_server.png
Androidアプリからファイルを送信して、サーバー側で保存、サーバーからアプリにステータスコードを返却する

実装

ローカルサーバー

Server.go
package controllers

import (
    "fmt"
    "net/http"
    "io/ioutil"
    "os"
)

func apiSampleHandler(w http.ResponseWriter, r *http.Request) {
    switch(r.Method) {
        case "POST":
            fmt.Println("POST")
            // アップロードしたファイルとヘッダーを取得 
            file, fileHeader, _ := r.FormFile ("upload_file") 
            fileName := fileHeader.Filename // ヘッダーからファイル名を取得
            defer file.Close()              // ファイルを最後にClose
            data, _ := ioutil.ReadAll(file) // ファイルを読み出し
            saveFile, _ := os.Create(fileName) // 保存用のファイルを生成
            defer saveFile.Close()          // 保存用のファイルを最後にClose
            _, err = saveFile.Write(data)   // ファイルに書き込み
            if err != nil {
                fmt.Println("can not write file")
                w.WriteHeader(http.StatusBadRequest)
                return
            }
        case "GET":
            fmt.Println("GET")
    }
    // 200:OKを返す 
    w.WriteHeader(http.StatusOK)
}

// main.goから呼び出してサーバーを起動
func StartWebServer() error {
    http.HandleFunc("/", apiSampleHandler)
    return http.ListenAndServe(":8080", nil)
}

main.goを実行し、サーバーを起動
http://localhost:8080 にアクセスして、サーバーが起動していることを確認

Android アプリ

1.Androidmanifest.xml

インターネットにアクセスするためのPermissionを定義

AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" />

Android 9.0からhttpの通信の設定がOFFになるのでusesCleartextTraficをtrueに設定

AndroidManifest.xml
<application
     省略
    android:usesCleartextTraffic="true">
    <activity android:name=".MainActivity">
        省略
    </activity>
</application>

2.ファイルを生成

Android端末のアプリ固有領域(/data/data/{package_name}/files配下)にテキストファイルを生成

File.kt
const val FILE_EXPAND = ".txt"

class File {
    fun makeTxtFile(context: Context, fileName: String, str: String) {
        try {
            context.openFileOutput(fileName + FILE_EXPAND, Context.MODE_PRIVATE).use {
                it.write(str.toByteArray())
            }
        } catch (e: IOException) {
            Log.e("File", "#makeTxtFile $e")
        }
    }
}

ファイルの生成を確認
Device File Explorer でデバイス上のファイルを表示する

3.サーバーアクセス

ファイルを読み込んで、http通信でファイルを送信する

Net.kt
 fun startConnection(context: Context, requestUrl: String, requestMethod: String, fileName: String): Pair<Int, String> {
        val url = URL(requestUrl)                      // URLオブジェクト生成
        // UrlConnectionオブジェクト生成
        val urlConnection = url.openConnection() as HttpURLConnection 
        var result = ""
        var responseCode = 0
        try {
            val boundary = "--------------------------" 
            urlConnection.requestMethod = requestMethod // POST, GETなど
            urlConnection.doOutput = true               // リクエストボディの送信
            urlConnection.doInput = true                // レスポンスボディの受信
            urlConnection.useCaches = false             // キャッシュの利用
            // multipart/form-data:複数のデータを送信、boundary:複数データ間の区切り
            urlConnection.setRequestProperty(
                "Content-Type",
                "multipart/form-data; boundary=$boundary" 
            )
            val filePath = context.filesDir             // アプリ固有領域のパス
            val file = File("$filePath/$fileName$FILE_EXPAND") // ファイルオブジェクトを生成
            FileInputStream(file).use { fileInputStream ->
                urlConnection.connect()                 // コネクションを確立
                DataOutputStream(urlConnection.outputStream).use {
                   it.writeBytes(                       // headerを設定
                       TWO_HYPHEN + boundary + LINE_END +
                               "Content-Disposition: form-data; name=\"upload_file\"; " +
                               "filename=\"$fileName$FILE_EXPAND\"$LINE_END" +
                               "Content-Type: application/octet-stream$LINE_END$LINE_END"
                   )
                   // ファイル書き込み
                   val buffer = ByteArray(BUFFER_SIZE)
                   var bytesRead: Int
                   do {
                       bytesRead = fileInputStream.read(buffer)
                       if (bytesRead == -1) break
                       it.write(buffer, 0, bytesRead)
                   } while (true)
                   it.writeBytes(                       // footerの設定
                        LINE_END + TWO_HYPHEN + boundary + TWO_HYPHEN + LINE_END
                   )
                   it.flush()
                }
            }
            responseCode = urlConnection.responseCode   // レスポンスコードを取得

            BufferedReader(InputStreamReader(urlConnection.inputStream)).use {
                val sb = StringBuffer()
                for (line in it.readLines()) {
                    line.let { sb.append(line) }
                }
                result = sb.toString()
            }
        } catch (e: Exception) {
            Log.e("Net", "#startConnection$e")
        } finally {
            urlConnection.disconnect()
        }
        return responseCode to result
    }
}

4.IPアドレスの確認

アクセスしたいサーバー(PC)のIPアドレスをcommand promptで以下を実行し確認

>ipconfig

5.PCとAndroid端末を同一のネットワーク環境に接続

6.Androidにて接続

Net#startConnectionのrequestUrlにhttp://{確認したIPアドレス}:8080を設定してアプリを実行

ファイルのアップロードを確認

PCにてmain.goと同じディレクトリを確認する
ファイルが作成されていれば完了

最後に

全体ソースはこちら
アクセス先やRequestMethod、ファイル名はアプリで動的に変更できるようにしています。

参考文献

Goサーバー側

Go言語でのファイルアップロード

Androidアプリ側

[Android] アプリ内にファイルを保存する FileOutputStream, FileInputStream
Upload File To Server - Android Example
[Android]kotlinでのwhile-FileInputStream.readエラー
【Kotlin】複数の値を返したい!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Golangの環境構築【goenv】

goenvとは

goenvはGoのバージョン管理バージョン管理ツールです。

goenvのインストール

Home brewの場合

$ brew install goenv

gitの場合
goenvのinstallation

$ git clone https://github.com/syndbg/goenv.git ~/.goenv

goenvのPATHを通す

設定ファイルにpathを記述します。(自身の使用しているシェルに記述)

$ echo 'export GOENV_ROOT="$HOME/.goenv"' >> ~/.zshrc
$ echo 'export PATH="$GOENV_ROOT/bin:$PATH"' >> ~/.zshrc
$ echo 'eval "$(goenv init -)"' >> ~/.zshrc

$ source ~/.zshrc   //変更を更新
$ goenv -v
goenv 2.0.0beta11

バージョンが確認できたら完了です。

Goをインストール

下記のコマンドでインストールできるバージョンのリストを表示

$ goenv install -l
1.2.2
  1.3.0
  1.3.1
  〜
  1.15rc2
  1.15.1
  1.15.2

任意のバージョンをインストールします。

$ goenv install 1.**.*

GoのPATHを通す

~/.zshrc
$ echo 'export PATH="$GOROOT/bin:$PATH"' >> ~/.zshrc
$ echo 'export PATH="$PATH:$GOPATH/bin"' >> ~/.zshrc

$ source ~/.zshrc

使用するバージョンを選択

インストールしたバージョンをglobalに設定します。また、バージョンへの切り替えとか。

$goenv global 1.**.*
$ go version
go version go1.**.* darwin/amd64

バージョンが確認できたら完了です。

VSCodeの環境構築

まずGoのプラグインをインストールします。
スクリーンショット 2020-10-17 17.06.37.png

Toolのインストール

 次に、便利なtoolたちをインストールしていきます。まず、設定を開きgo.use language serverと検索してチェックがついているか確認します。
 確認したらshift + ⌘ + Pですべてのコマンドの表示を開き、Go: Install/Update Toolsと打ちこんだらgocodegocode-gomod以外(コードの補完機能はgoplsで行うため)を選択してインストールします。もし、ここにgoplsがなければ検索タブにgoplsと打ってみてください。
スクリーンショット 2020-10-17 17.21.52.png

任意でsettings.jsonの設定

インストールが終わったら、下記をsettings.jsonに追記します。

settings.json
"go.useLanguageServer": true,
    "[go]": {
        "editor.formatOnSave": true,
        "editor.codeActionsOnSave": {
            "source.organizeImports": true,
        },
        "editor.snippetSuggestions": "none"
    },
    "gopls": {
        "hoverKind": "SynopsisDocumentation",
        "usePlaceholders": true,
        "linkTarget": "pkg.go.dev",
        "staticcheck": false,        
        "completionDocumentation": true,        
        "completeUnimported": true,        
        "deepCompletion": true
    },
    "files.autoSave": "afterDelay"

以上で完了です!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Golang] go test -cover 時にカバレッジが指定したパーセンテージ以下の場合に失敗(ステータスを1)にしたい

Go 言語でカバレッジの合格ラインを指定したい

go test -coverカバレッジ率が低くてもステータス 0(ゼロ)で正常終了してしまう。

$ # カバレッジ付きでユニットテストを実行する
$ go test -cover ./src
ok      github.com/KEINOS/sample/src       coverage: 62.5% of statements

$ # ステータス 0 で正常終了してしまう
$ echo $?
0

n パーセント以下は失敗」もしくは「n% より高い場合にパスさせる」といった、指定したパーセンテージよりカバレッジが低い場合にステータス 1 で終了させたい

Golang に標準装備されているユニット・テストで、カバレッジを表示させる際に、カバー率が低い場合に失敗させたかったのです。Travis CI や GitHub Actions などの CI とか。

「go test cover カバレッジ パーセンテージ 指定」とググってもカバレッジの説明ばかりで、カバレッジの合格ラインの指定方法について分からなかったので、自分のググラビリティとして。

TL; DR

Go v1.15.2 現在、go test-cover には合格ラインを指定するオプションを標準で持っていません。

しかし、testing.CoverMode() でカバー率を取得できるので TestMain() に条件文を組み込むことでパーセンテージを指定することができます。

TS; DR

メインのテストに以下を指定
package (
    "fmt"
    "testing"
)

// カバー率(0.8 以上で合格)
var thresholdCoverage = 0.8

func TestMain(m *testing.M) {
    var returnCode = m.Run()
    if returnCode == 0 && testing.CoverMode() != "" {
        var rateCoverage = testing.Coverage()
        if rateCoverage < thresholdCoverage {
            fmt.Println("テストはパスしましたが。カバレッジに失敗しました。カバレッジ率:", rateCoverage)
            returnCode = -1
        }
    }
    os.Exit(returnCode)
}
  • 動作確認: Go v1.15.2 @ Alpine Linux v3.12
  • 参考文献: 回答 | "fail unit tests if coverage is below certain percentage" @ StackOverflow

参考文献

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Golang】指定したカバレッジ以下で失敗(終了ステータスを1に)させる go test -cover 時のパーセンテージ指定

Go 言語でカバレッジの合格ラインを指定したい

go test -coverカバレッジ率が低くてもステータス 0(ゼロ)で正常終了してしまう。

$ # カバレッジ付きでユニットテストを実行する
$ go test -cover ./src
ok      github.com/KEINOS/sample/src       coverage: 62.5% of statements

$ # ステータス 0 で正常終了してしまう
$ echo $?
0

n パーセント以下は失敗」もしくは「n% より高い場合にパスさせる」といった、指定したパーセンテージよりカバレッジが低い場合にステータス 1 で終了させたい

Golang に標準装備されているユニット・テストで、カバレッジを表示させる際に、カバー率が低い場合に失敗させたかったのです。Travis CI や GitHub Actions などの CI とか。

「go test cover カバレッジ パーセンテージ 指定」とググってもカバレッジの説明ばかりで、カバレッジの合格ラインの指定方法について分からなかったので、自分のググラビリティとして。

TL; DR

Go v1.15.2 現在、go test-cover には合格ラインを指定するオプションを標準で持っていません。

しかし、testing.CoverMode() でカバー率を取得できるので TestMain() に条件文を組み込むことでパーセンテージを指定することができます。

TS; DR

メインのテストに以下を指定
package (
    "fmt"
    "testing"
)

// カバー率(0.8 以上で合格)
var thresholdCoverage = 0.8

func TestMain(m *testing.M) {
    var returnCode = m.Run()
    if returnCode == 0 && testing.CoverMode() != "" {
        var rateCoverage = testing.Coverage()
        if rateCoverage < thresholdCoverage {
            fmt.Println("テストはパスしましたが。カバレッジに失敗しました。カバレッジ率:", rateCoverage)
            returnCode = -1
        }
    }
    os.Exit(returnCode)
}
  • 動作確認: Go v1.15.2 @ Alpine Linux v3.12
  • 参考文献: 回答 | "fail unit tests if coverage is below certain percentage" @ StackOverflow

参考文献

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む