Обновить
0
Владимир@Ponywka

Программист-любитель. Единорогокопытный.

Отправить сообщение

Посмотрите в сторону роутеров семейства Cudy WR3000. На 4PDA есть ветка где сравниваются все роутеры из этого семейства - можно выбрать любой по душе.

Эх... Кликбейт... Я когда увидел, что бинарник весит 2гб, то аж сильно удивился что там могло быть, что автор говорит аж о целых 200 раз сжатия... а оказывается речь зашла о том, что автор изначально в образ весь SDK тянул, что как бы не удивительно, что размер образа очень сильно разбух :/

Ну... Начну тогда по порядку...

P.s. Приведённые куски кода будут лишь примерными - ибо в истории нормальные куски кода не сохранились.

Для начала мне нужно было сделать заготовленные запросы, чтобы например не повторять один и тот же код в разных тестах.

func RegisterUser(req *requests.User) *cute.Test {
	return &cute.Test{
		Name: "Registering user",
		Middleware: nil,
		Request: &cute.Request{
			Builders: []cute.RequestBuilder{
				cute.WithMethod(http.MethodPost),
				cute.WithURI(constants.GenURI("/api/v1/users")),
				cute.WithMarshalBody(req),
			},
		},
		Expect: &cute.Expect{
			Code: http.StatusCreated,
		},
	}
}

func Test_RegisterUser(t *testing.T) {
	cute.NewTestBuilder().
		Title("Register Test Users").
		CreateTableTest().
		PutTests(
			RegisterUser(&requests.User{Username: "TestUser1"}),
			RegisterUser(&requests.User{Username: "ИнвалидЮзернаме"}), // этап, который должен упасть и повалить все последующие этапы
			RegisterUser(&requests.User{Username: "TestUser2"}),
		).
		ExecuteTest(context.Background(), t)
}

Запускаем, получаем что-то в стиле:

Test_RegisterUser/Register Test Users:
#1: ✅ Register User
#2: ❌ Register User
#3: ✅ Register User

Что-ж... Ресёрчим - читаем код - убеждаемся, что мы не можем фейлить последующие тесты. Пишем костыли.

func NewTest(t *testing.T, testName string, tags ...string) *common.Common {
	providerCfg := manager.NewProviderConfig().
		WithFullName("ServiceName").
		WithPackageName("serviceName").
		WithSuiteName("ServiceName")
	newProvider := manager.NewProvider(providerCfg)
	newProvider.NewTest(testName, "serviceName", tags...)

	newT := common.NewT(t)
	newT.SetProvider(newProvider)

	return newT
}

func Test_RegisterUser(t *testing.T) {
	newT := NewTest(t, "Register Test Users")
	tests := []*cute.Test{
		RegisterUser(&requests.User{Username: "TestUser1"}),
		RegisterUser(&requests.User{Username: "ИнвалидЮзернаме"}), // этап, который должен упасть и повалить все последующие этапы
		RegisterUser(&requests.User{Username: "TestUser2"}),
	}
	for _, test := range tests {
		res := test.Execute(context.Background(), newT)
		if res.GetErrors() != nil {
			newT.FailNow()
		}
	}
}

Запускаем - у нас внезапно теперь выбивает паники:

    errors_handling.go:28: Test panicked: runtime error: invalid memory address or nil pointer dereference
        goroutine 20 [running]:
        runtime/debug.Stack()
        	/home/ponywka/sdk/go1.22.6/src/runtime/debug/stack.go:24 +0x5e
        github.com/ozontech/allure-go/pkg/framework/core/common.(*Common).Run.func1.3()
        	/home/ponywka/go/pkg/mod/github.com/ozontech/allure-go/pkg/framework@v0.6.33/core/common/common.go:337 +0x65
        panic({0x884f20?, 0xca5a80?})
        	/home/ponywka/sdk/go1.22.6/src/runtime/panic.go:770 +0x132
        github.com/ozontech/cute.(*Test).buildRequest(0xc00012e640, {0x9be088, 0xc0001d8460})
        	/home/ponywka/go/pkg/mod/github.com/ozontech/cute@v1.1.21/test.go:472 +0x28f

Смотрим где упало - обнаруживаем что падает при маршалинге:

func (it *Test) buildRequest(ctx context.Context) (*http.Request, error) {
	// ...
	body := o.body
	if o.bodyMarshal != nil {
		body, err = it.jsonMarshaler.Marshal(o.bodyMarshal) // Здесь падает

		if err != nil {
			return nil, err
		}
	}
	// ...
}

Чтож... Воспользуемся мидлами:

func WriteJSON(data interface{}) func(*http.Request) error {
	return func(req *http.Request) error {
		req.Header.Set("Content-Type", "application/json")
		buf := bytes.NewBuffer(nil)
		err := json.NewEncoder(buf).Encode(data)
		if err != nil {
			return err
		}
		req.Body = io.NopCloser(buf)
		return nil
	}
}

func RegisterUser(req *requests.User) *cute.Test {
	return &cute.Test{
		Name: "Registering user",
		Middleware: &cute.Middleware{
			Before: []cute.BeforeExecute{
				WriteJSON(req),
			},
		},
		Request: &cute.Request{
			Builders: []cute.RequestBuilder{
				cute.WithMethod(http.MethodPost),
				cute.WithURI(constants.GenURI("/api/v1/users")),
			},
		},
		Expect: &cute.Expect{
			Code: http.StatusCreated,
		},
	}
}

Запускаем - аллилуя - хоть у нас и не отображаются пропущенные действия - дальнейшие этапы не запускаются!

ServiceName/Register Test Users:
#1: ✅ Register User
#2: ❌ Register User

Что-ж... С первой проблемой разобрались - разбираемся дальше. Пробуем прокинуть переменные с этапов выше в последующие этапы

func ParseResponse(a interface{}) func(*http.Response) error {
	return func(response *http.Response) error {
		if reflect.ValueOf(a).IsNil() {
			return nil
		}
		b, err := io.ReadAll(response.Body)
		if err != nil {
			return err
		}
		err = json.Unmarshal(b, a)
		if err != nil {
			return err
		}
		return nil
	}
}

func RegisterUser(req *requests.User, res *responses.User) *cute.Test {
	return &cute.Test{
		Name: "Registering user",
		Middleware: &cute.Middleware{
			Before: []cute.BeforeExecute{
				WriteJSON(req),
			},
		},
		Request: &cute.Request{
			Builders: []cute.RequestBuilder{
				cute.WithMethod(http.MethodPost),
				cute.WithURI(constants.GenURI("/api/v1/users")),
			},
		},
		Expect: &cute.Expect{
			Code: http.StatusCreated,
			AssertResponse: []cute.AssertResponse{
				ParseResponse(res)
			},
		},
	}
}

func Test_RegisterUser(t *testing.T) {
	newT := NewTest(t, "Register Test Users")
	user1 := new(responses.User)
	user2 := new(responses.User)
	tests := []*cute.Test{
		RegisterUser(&requests.User{Username: "TestUser1"}, user1),
		RegisterUser(&requests.User{Username: "TestUser2"}, user2),
	}
	for _, test := range tests {
		res := test.Execute(context.Background(), newT)
		if res.GetErrors() != nil {
			newT.FailNow()
		}
	}
	t.Log(user1.Token)
	t.Log(user2.Token)
}

Проверяем - вроде работает - но уже код становится страшнее и страшнее...

И на самом деле в процессе написания комментария я понял, что мог попробовать ещё такую стратегию - она бы решила часть проблем:

func Test_RegisterUser(t *testing.T) {
	newT := NewTest(t, "Register Test Users")
	
	user1 := new(responses.User)
	res := RegisterUser(&requests.User{Username: "TestUser1"}, user1).Execute(context.Background(), newT)
	if res.GetErrors() != nil {
		newT.FailNow()
	}
	t.Log(user1.Token)
		
	user2 := new(responses.User)
	res := RegisterUser(&requests.User{Username: "TestUser2"}, user2).Execute(context.Background(), newT)
	if res.GetErrors() != nil {
		newT.FailNow()
	}
	t.Log(user2.Token)
}

Расписал бы и далее что делал, но увы, комментарий и так уже отнял достаточно времени :\

Такой вопрос - вы хоть сами пробовали писать тесты используя Cute? Это замечательно, что в примере есть тесты на фиксированных данных, но когда речь заходит до реального тестирования API - это боль. Допустим мне нужно выполнить сложный запрос состоящий из нескольких этапов (предположим это будет условный ВКонтакте):

  • Создать пользователя 1

  • Создать пользователя 2

  • Отправить запрос в друзья пользователю 2 от лица пользователя 1

  • Принять запрос в друзья пользователя 1 от лица пользователя 2

  • Создать чат с пользователем 2 от лица пользователя 1

Допустим, что в API ошибка, и на третьем этапе произошла ошибка. Дальнейшие тесты не падают. Приходится писать костыли.

Внезапно оказывается, что данные не прокидываются в следующие тесты. Опять пишем костыли.

Внезапно теперь тесты падают по причине "invalid memory address or nil pointer dereference". Приходится ещё больше костылей писать, сложность тестов увеличивается - профита никакого.

Какой смысл от этого фреймворка, если он не упрощает, а только наоборот замедляет написание тестов? Документации нету, большую часть тестов приходится писать методом тыка. Но зато в посте как всё замечательно выглядит, с зелёными галочками и красивым кодом!

А это точно Apple Watch Ultra, а не китайское подпольное подделие на них?

Я не нашел информации на счёт запуска Android под Apple Watch.

Так а какая разница? Под PSP делали неоригинальные корпуса смастеренные каким-то человеком никак не относящимся с компании Sony. В чем проблема будет производителям корпусов делать точно также и с Steam Desk?

Если тебе нужен будет оригинальный корпус, то если не ошибаюсь, компания Steam и так будет их продавать как отдельную запчасть (МОГУ ОШИБАТЬСЯ)

Информация

В рейтинге
Не участвует
Откуда
Лиски (Воронежская обл.), Воронежская обл., Россия
Дата рождения
Зарегистрирован
Активность