πŸ€” Π§Ρ‚ΠΎ Ρ‚Π°ΠΊΠΎΠ΅ ΠΌΠΎΠΊΠΈ (mocks) ?



Моки (mocks) β€” это ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΈΠΌΠΈΡ‚ΠΈΡ€ΡƒΡŽΡ‚ ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠ΅ Ρ€Π΅Π°Π»ΡŒΠ½Ρ‹Ρ… ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² Π² тСстах. Они ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ΡΡ для изоляции тСстируСмого ΠΊΠΎΠ΄Π° ΠΎΡ‚ зависимостСй, Ρ‚Π°ΠΊΠΈΡ… ΠΊΠ°ΠΊ Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ…, внСшниС API, файловая систСма ΠΈ Π΄Ρ€ΡƒΠ³ΠΈΠ΅ сСрвисы. Моки ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‚ ΡΠΎΡΡ€Π΅Π΄ΠΎΡ‚ΠΎΡ‡ΠΈΡ‚ΡŒΡΡ Π½Π° тСстировании ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎΠΉ части ΠΊΠΎΠ΄Π° Π±Π΅Π· нСобходимости Π·Π°Π΄Π΅ΠΉΡΡ‚Π²ΠΎΠ²Π°Ρ‚ΡŒ Ρ€Π΅Π°Π»ΡŒΠ½Ρ‹Π΅ рСсурсы, Ρ‡Ρ‚ΠΎ Π΄Π΅Π»Π°Π΅Ρ‚ тСсты Π±ΠΎΠ»Π΅Π΅ быстрыми ΠΈ прСдсказуСмыми.



🚩 Π—Π°Ρ‡Π΅ΠΌ ΠΎΠ½ΠΈ Π½ΡƒΠΆΠ½Ρ‹?



πŸŸ Π˜Π·ΠΎΠ»ΡΡ†ΠΈΡ тСстов: ΠŸΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‚ ΠΈΠ·ΠΎΠ»ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ тСстируСмый ΠΊΠΎΠ΄ ΠΎΡ‚ Π΅Π³ΠΎ зависимостСй, Ρ‡Ρ‚ΠΎ ΠΏΠΎΠΌΠΎΠ³Π°Π΅Ρ‚ ΡƒΠ±Π΅Π΄ΠΈΡ‚ΡŒΡΡ, Ρ‡Ρ‚ΠΎ тСстируСмая Π»ΠΎΠ³ΠΈΠΊΠ° Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½ΠΎ сама ΠΏΠΎ сСбС.

πŸŸ ΠšΠΎΠ½Ρ‚Ρ€ΠΎΠ»ΡŒ Π½Π°Π΄ срСдой тСстирования: Π‘ ΠΌΠΎΠΊΠ°ΠΌΠΈ ΠΌΠΎΠΆΠ½ΠΎ Ρ‚ΠΎΡ‡Π½ΠΎ ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌΡ‹Π΅ значСния ΠΈ ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠ΅ зависимостСй, Ρ‡Ρ‚ΠΎ позволяСт ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ прСдсказуСмыС ΠΈ повторяСмыС тСсты.

πŸŸ Π£ΡΠΊΠΎΡ€Π΅Π½ΠΈΠ΅ тСстов: ИспользованиС ΠΌΠΎΠΊΠΎΠ² вмСсто Ρ€Π΅Π°Π»ΡŒΠ½Ρ‹Ρ… рСсурсов (Ρ‚Π°ΠΊΠΈΡ… ΠΊΠ°ΠΊ Π±Π°Π·Ρ‹ Π΄Π°Π½Π½Ρ‹Ρ… ΠΈΠ»ΠΈ внСшниС API) Π΄Π΅Π»Π°Π΅Ρ‚ тСсты быстрСС ΠΈ сниТаСт Π·Π°Ρ‚Ρ€Π°Ρ‚Ρ‹ Π½Π° ΠΈΡ… Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅.

πŸŸ Π’Π΅ΡΡ‚ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ ошибок ΠΈ ΠΊΡ€Π°ΠΉΠ½ΠΈΡ… случаСв: ΠŸΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‚ Π»Π΅Π³ΠΊΠΎ ΠΌΠΎΠ΄Π΅Π»ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ошибки ΠΈ ΠΊΡ€Π°ΠΉΠ½ΠΈΠ΅ случаи, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΌΠΎΠ³ΡƒΡ‚ Π±Ρ‹Ρ‚ΡŒ Ρ‚Ρ€ΡƒΠ΄Π½ΠΎ воспроизвСсти с Ρ€Π΅Π°Π»ΡŒΠ½Ρ‹ΠΌΠΈ зависимостями.



🚩Как ΠΈΡ… ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΌΠΎΠΊΠΈ ?



Для создания ΠΈ использования ΠΈΡ… часто ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΡŒΠ½Ρ‹Π΅ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ, Ρ‚Π°ΠΊΠΈΠ΅ ΠΊΠ°ΠΊ gomock ΠΈΠ»ΠΈ testify/mock. Рассмотрим ΠΏΡ€ΠΈΠΌΠ΅Ρ€ использования Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ testify/mock.



Установка Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ testify

go get github.com/stretchr/testify




// api.go

package main



type APIClient interface {

FetchData(endpoint string) (string, error)

}



func GetData(client APIClient, endpoint string) (string, error) {

data, err := client.FetchData(endpoint)

if err != nil {

return "", err

}

return data, nil

}




Π‘ΠΎΠ·Π΄Π°Π΄ΠΈΠΌ ΠΌΠΎΠΊ для интСрфСйса APIClient с использованиСм Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ testify/mock.

// api_test.go

package main



import (

"errors"

"testing"



"github.com/stretchr/testify/mock"

"github.com/stretchr/testify/assert"

)



// MockAPIClient is a mock type for the APIClient interface

type MockAPIClient struct {

mock.Mock

}



func (m *MockAPIClient) FetchData(endpoint string) (string, error) {

args := m.Called(endpoint)

return args.String(0), args.Error(1)

}



func TestGetData(t *testing.T) {

// Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΠΌΠΎΠΊΠ°

mockClient := new(MockAPIClient)



// Настройка ΠΌΠΎΠΊΠ° для Π²ΠΎΠ·Π²Ρ€Π°Ρ‚Π° Π΄Π°Π½Π½Ρ‹Ρ…

mockClient.On("FetchData", "test-endpoint").Return("mocked data", nil)



// Π’Ρ‹Π·ΠΎΠ² тСстируСмой Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ

data, err := GetData(mockClient, "test-endpoint")



// ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠ²

assert.NoError(t, err)

assert.Equal(t, "mocked data", data)



// ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° Π²Ρ‹Π·ΠΎΠ²Π° ΠΌΠΎΠΊΠ°

mockClient.AssertExpectations(t)

}



func TestGetDataWithError(t *testing.T) {

// Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΠΌΠΎΠΊΠ°

mockClient := new(MockAPIClient)



// Настройка ΠΌΠΎΠΊΠ° для Π²ΠΎΠ·Π²Ρ€Π°Ρ‚Π° ошибки

mockClient.On("FetchData", "error-endpoint").Return("", errors.New("fetch error"))



// Π’Ρ‹Π·ΠΎΠ² тСстируСмой Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ

data, err := GetData(mockClient, "error-endpoint")



// ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠ²

assert.Error(t, err)

assert.Equal(t, "", data)



// ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° Π²Ρ‹Π·ΠΎΠ²Π° ΠΌΠΎΠΊΠ°

mockClient.AssertExpectations(t)

}




Π‘Ρ‚Π°Π²ΡŒ πŸ‘ ΠΈ Π·Π°Π±ΠΈΡ€Π°ΠΉ πŸ“š Π‘Π°Π·Ρƒ Π·Π½Π°Π½ΠΈΠΉ