Tarkibga o'tish

Go kodini tekshirish vositalari

Formatlash, statik tahlil va test turli muammolarni aniqlaydi. Ularni bir xil ish jarayonida ketma-ket bajarish kodni review va release oldidan tekshirishni soddalashtiradi.

Formatlash

Bitta faylni formatlash:

gofmt -w main.go

gofmt -w ko‘rsatilgan faylni standart Go uslubiga keltirib, natijani shu faylga yozadi. Moduldagi paketlarni Go buyrug‘i orqali formatlash:

go fmt ./...

go fmt paketlarni tanlaydi va ular uchun gofmtni ishga tushiradi. Formatlash sintaktik ko‘rinishni birxillashtiradi, lekin biznes mantiq xatosini topmaydi.

Statik tahlil

go vet kodni ishga tushirmasdan, kompilyator qabul qilishi mumkin bo‘lgan ayrim shubhali konstruksiyalarni izlaydi:

go vet ./...

Masalan, u ayrim noto‘g‘ri format satrlari yoki nusxalanmasligi kerak bo‘lgan sinxronizatsiya qiymatlari bilan bog‘liq muammolarni ko‘rsatishi mumkin. go vet barcha xatolarni topmaydi va test o‘rnini bosmaydi.

Test va race tekshiruvi

Butun modul testlari:

go test ./...

Concurrent kod yo‘llarini race detector bilan tekshirish:

go test -race ./...

Oddiy test kutilgan xatti-harakatni tekshiradi. Race detector esa testlar bajargan yo‘llarda sinxronizatsiyasiz umumiy xotira murojaatlarini qidiradi. Ular bir-birini almashtirmaydi.

Tavsiya etilgan ketma-ketlik

Kichik loyiha uchun quyidagi tekshiruvlar yetarli boshlang‘ich jarayon bo‘ladi:

go fmt ./...
go vet ./...
go test ./...
go test -race ./...

Formatlash fayllarni o‘zgartirishi mumkin. Shu sabab buyruqlardan keyin git diffni ko‘ring va faqat kutilgan o‘zgarishlarni saqlang. Race tekshiruvi oddiy testdan sekinroq, ammo concurrent kodli loyiha uchun release yoki CI oldidan muhim.

Katta loyihada bu buyruqlar CI’da ham bajariladi. Lokal va CI bir xil buyruqlardan foydalansa, xato push qilingandan keyin emas, oldinroq aniqlanadi.

Vositalar chegarasi

  • formatlash kod uslubini birxillashtiradi;
  • go vet ma’lum shubhali konstruksiyalarni topadi;
  • test talab qilingan xatti-harakatni tekshiradi;
  • race detector bajarilgan yo‘llardagi data racelarni qidiradi.

Bitta tekshiruvdan muvaffaqiyatli o‘tish qolganlarini keraksiz qilmaydi. Performance uchun esa alohida benchmark va profiling kerak.

Xulosa

Go loyihasida go fmt, go vet, go test va go test -raceni izchil ishlating. Har bir vositaning vazifasi boshqa: format, statik shubha, xatti-harakat va concurrent xotira xavfsizligi alohida tekshiriladi.

Misollar

1. gofmt -d bilan farqni ko‘rish

Bu misolda gofmt -d faylni o‘zgartirmasdan format farqini chiqaradi.

package main

import "fmt"

func main() {
    numbers := []int{3, 1, 4}
    fmt.Println(numbers)
}

Fayl ataylab noto‘g‘ri chekinish bilan yozilsa, gofmt -d main.go kerakli o‘zgarishni diff sifatida ko‘rsatadi. Buyruq faylga yozmaydi. Yuqoridagi blok esa gofmtdan keyingi to‘g‘ri ko‘rinishni ko‘rsatadi.

2. gofmt -w bilan faylni formatlash

Bu misolda map literalining standart joylashuvi ko‘rsatiladi.

package main

import "fmt"

func main() {
    ports := map[string]int{
        "http":  80,
        "https": 443,
    }
    fmt.Println(ports)
}

gofmt -w main.go natijani bevosita faylga yozadi. 80 odatiy HTTP porti, 443 esa HTTPS porti sifatida tanlangan. gofmt ikki qiymatni o‘qish qulay bo‘lishi uchun ustunlarni tekislaydi, ammo portlarning to‘g‘riligini tekshirmaydi.

3. Formatlanmagan fayllarni ro‘yxatlash

Bu misol struct qiymatlarini standart formatda saqlaydi. gofmt -l . esa joriy katalogdagi format talab qiladigan Go fayllarini sanaydi.

package main

import "fmt"

type Server struct {
    Host string
    Port int
}

func main() {
    server := Server{
        Host: "localhost",
        Port: 8080,
    }
    fmt.Println(server)
}

-l faqat fayl nomlarini chiqaradi va ularni o‘zgartirmaydi. Hech qanday nom chiqmasa, tekshirilgan fayllar gofmt talabiga mos. 8080 lokal dasturlarda ko‘p ishlatiladigan muqobil port sifatida tanlangan.

4. gofmt -s bilan sodda yozuvga o‘tish

Bu misolda slice oxirigacha bo‘lgan kesma ataylab uzun shaklda yozilgan.

package main

import "fmt"

func main() {
    values := []int{10, 20, 30, 40}
    last := values[2:len(values)]
    fmt.Println(last)
}

gofmt -s -d main.go bu ifodani values[2:] ko‘rinishiga soddalashtirishni taklif qiladi. 2 indeksi uchinchi elementdan boshlaydi. Yuqori chegara len(values) bo‘lgani uchun oxirgi elementgacha olinadi; slice kesmasida yuqori chegara natijaga kirmaydi.

5. Butun modulni go fmt bilan tekshirish

Bu misol alohida paket ichidagi eksport qilinadigan funksiyaga o‘xshash kichik hisobni ko‘rsatadi.

package main

import "fmt"

func Total(prices []int) int {
    total := 0
    for _, price := range prices {
        total += price
    }
    return total
}

func main() {
    fmt.Println(Total([]int{12, 8, 5}))
}

Modul ildizida go fmt ./... bajarilsa, barcha ichki paketlar tanlanadi. total 0dan boshlanadi, chunki yig‘indiga birinchi narx hali qo‘shilmagan. Formatlash funksiya natijasi 25 ekanini tekshirmaydi; buni test tekshiradi.

6. go vet bilan format satri xatosini topish

Bu misol kompilyatsiya qilinadi, ammo Printf formati argument turiga mos emas.

package main

import "fmt"

func main() {
    count := "uchta"
    fmt.Printf("Fayllar soni: %d\n", count)
}

%d butun son kutadi, count esa string. go run buni maxsus diagnostika matni bilan chiqarishi mumkin, go vet ./... esa xatoni oldindan ko‘rsatadi. Tuzatish uchun %d o‘rniga %s yoziladi. Misol go vet kompilyator qabul qilgan ayrim shubhali kodlarni topishini ko‘rsatadi.

7. go test bilan paketlarning kompilyatsiyasini tekshirish

Bu misolda test fayli bo‘lmasa ham, go test ./... paketni kompilyatsiya qiladi.

package main

import "fmt"

func average(total, count int) int {
    if count == 0 {
        return 0
    }
    return total / count
}

func main() {
    fmt.Println(average(30, 3))
}

go test ./... testlari yo‘q paket uchun [no test files] yozishi mumkin, lekin kod baribir kompilyatsiyadan o‘tadi. count == 0 tekshiruvi nolga bo‘lishning oldini oladi. 30 / 3 natijasi aniq 10 bo‘lgani uchun butun sonli misol tanlangan.

8. Race tekshiruvini butun modulga qo‘llash

Bu misolda slice ketma-ket to‘ldiriladi va umumiy xotiraga concurrent murojaat yo‘q.

package main

import "fmt"

func main() {
    values := make([]int, 3)
    for index := range values {
        values[index] = (index + 1) * 10
    }
    fmt.Println(values)
}

go test -race ./... testlar bajargan kod yo‘llarini race detector bilan tekshiradi. Slice elementlari dastlab 0, chunki intning nol qiymati 0. Indeks 0dan boshlanadi, natijani 10dan boshlash uchun hisobda index + 1 ishlatilgan.

9. Coverage va test muvaffaqiyatini alohida baholash

Bu misolda chegara qiymatiga ega sodda funksiya bor. Uning turli yo‘llari testlarda alohida bajarilishi kerak.

package main

import "fmt"

func discount(total int) int {
    if total < 100 {
        return 0
    }
    return 10
}

func main() {
    fmt.Println(discount(100))
}

Test fayli qo‘shilgach go test -cover ./... bajarilgan statementlar ulushini ko‘rsatadi. Shartda < 100 ishlatilgani uchun aynan 100 chegara qiymati chegirma oladi. Coverage yuqori bo‘lsa ham, kutilgan natijalar to‘g‘ri tanlanmagan bo‘lishi mumkin.

10. Tekshiruvlarni bitta tartibda bajarish

Bu misol barcha asosiy vositalar tekshirishi mumkin bo‘lgan kichik, ishlaydigan dasturni beradi.

package main

import (
    "fmt"
    "strings"
)

func normalize(words []string) string {
    cleaned := make([]string, 0, len(words))
    for _, word := range words {
        cleaned = append(cleaned, strings.TrimSpace(word))
    }
    return strings.Join(cleaned, ", ")
}

func main() {
    words := []string{" Go ", " test ", " vet "}
    fmt.Println(normalize(words))
}

Tekshiruvni go fmt ./..., go vet ./..., go test ./... va go test -race ./... tartibida bajarish mumkin. cleaned uzunligi 0dan boshlanadi, chunki hali hech bir so‘z tozalanmagan. Uning sig‘imi len(words)ga teng: har bir kirish elementi uchun bittadan natija kutiladi.