Skip to content

gggittt/UiTest_Framework-unity

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 

Repository files navigation

Тестовое в Кефир.

ответ от компании:

Большинство замечаний к тестовому фреймворку, предоставленному в задании, справедливы, но сам фреймворк создавался исключительно для целей ТЗ и не применяется для других задач. На продуктах используются похожие подходы и принципы к автотестам, но используемые инструменты естественно отличаются от предоставленного, активно развиваются и находятся вместе с кодом проектов.

  • считаю такой подход непродуктивным. "Основной-то фреймворк у нас нормальный, а этот джуновский код - только для тестового." (если это вообще правда) Если Вы тестируете кандидатов на джуновском коде, то и получите тех, кто более приспособлен к работе с джуновским кодом.

Более уважительным к времени кандидата был бы подход, где предоставлялся бы +- приближенный к реальному код, т.е. без детских ошибок и с документаций (или "самодокуентируемый" код, где названия сущностей дают недвусмысленное понимание того, что сущности делают). Иначе выходит, что кандидат, работая в своей карьере с норм кодом, должен на время тестового, нырнуть в фреймворк с грубыми ошибками, а после тестового на работе снова вынырнуть в норм код? Зачем?

Фидбэка ждал 2.5 дня.


into

В ходе знакомства с фреймворком для автоматизации, у меня возникало много вопросов, ответов на которые в коде я не нашёл. Обычно знакомство с такими объемными штуками происходит на онбординге, где будущего пользователя фреймворка сразу погружают в контекст, дают примеры использования, сообщают в чём фреймворк хорош и в чём бесполезен, возможные баги, неочевидности и т.п. У меня такой опции нет, поэтому оставляю фидбэк здесь в тексте.

В идеале (особенно если его часто изучают новые люди) для фреймворка иметь документацию. Можно как просто в тексте, так и в виде примеров, или описания в ///<summary> к типам и членам класса. Можно не для всего кода, но хотя бы для неочевидных мест.

Хорошие примеры документации (прямо на главной странице, в readmi): https://github.com/Cysharp/R3, https://github.com/modesttree/Zenject, https://github.com/neuecc/UniRx, https://github.com/bazyleu/UniState

Идея фреймворка интересная. Но я в последнее время в, скажем так, синьорном комьюнити Unity вижу больше подвижек в отделении моделей (POCO) от Unity корутин и MonoBehaviour. Плюсы такого подхода:

  1. тесты будут более легковесными, время выполнения тестов уменьшается.
  2. тесты становятся "пользователями кода", чем подталкивают программистов писать более качественный код. В предоставленном мне фреймворке же всё жёстко на корутинах. Разница подходов (вкупе с другими неочевидносятми в коде) ещё больше запутывает.

Стоит также добавить, что большие системы и наследование стоит использовать аккуратно. Пару слов об этом на этом стриме K-Syndicate (см таймкод 1:13:34): UNIT TESTING ⚡️ Правильно внедряем unit-тесты в Unity проект

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

Штуки, которые меня замедляли

1. методы в interface ICheats. Возвращаемый тип, имя метода и аргументы не сходятся по смыслу.

1.1 Методы с Get в названии по смыслу должны что-то возвращать. Здесь же (понял только когда открыл dll) должно быть AddX. Но лучше даже уточнить куда "Add" - в верстак, инвентарь, или добавляется бонус "к дереву" за срубку дерева.

image

1.2 должно быть "IsXEmpty", т.к. тут ничего не "считается"("Count" в названии не нужен).

image

1.2.1 Метод CountIsEmpty, исходя только из названия и возвращаемого типа, скорее бы выглядел как-то так:

image

*просто для примера. В предоставленном проекте Inventory и Cell другие.

⚠️ Naming в программировании очень важен. Неправильно названный метод ведёт к его неправильному использованию, и далее к багам. По написанному мной методу видно, насколько он мог бы отличаться от того что в фреймворке. Извне, не залезая в реализацию метода, легко понять метод неправильно. Если же закапываться в реализацию каждого метода, то на изучение кода уйдёт несколько рабочих дней.

1.3 Под методом TreeFelled могла бы скрываться как логика IsTreeFelled, так и MarkTreeAsFelled, где return это bool markesSuccessfully

image image

1.4 GetGmGo(); чтобы понять что значит сокращение "Gm", пришлось снова лезть в dll.

2. ButtonsGroup.cs

2.1 Лучше не держать такую объёмную логику в конструкторе. И в любом случает лучше разбить на методы или локальные функции по нескольку строк. Code should read like well-written prose and be clean, lean, and easy to maintain.

2.2 в используемых в классе словарях ключом было бы лучше сделать enum. Это избавит от возможных опечаток, и это даст человеку, изучающему фреймворк посмотреть сразу список всех опций.

image

В идеале, эти словари обернуть в свои классы, чтобы их назначении стало понятнее.

3. Дубляж строковых id.

Например, в UiTestContext.Inventory { get { return _buttons["inventory"]; } } //строка "inventory"

и в UiTest_Framework\UiTest\UiTestDll\UiTest\Context\Consts\Inventory\Inventory.Id //тоже строка "inventory"

image

При расширении кода кто-то может забыть, что всё слово в нижнем регистре, и попытаться обратиться через buttons["INVENTORY"] или buttons["Inventory"], в результате чего произойдёт ошибка. Лучше держать строку в одном месте, а во всех других местах всегда обращаться через Inventory.Id, или организовать отдельный класс Constants. Эта ситуация описывается в принципе DRY.

4. Дубляж кода

в половине методов Commands.cs. Лучше переиспользовать код в приватном методе/методах, если логика частично совпадает.

image

5. Нарушение LSP (нужно разделить интерфейсы)

В половине реализующих IUiTestChecker (например, UseButtonIsActiveChecker.cs)

public void Init()
{
    throw new System.NotImplementedException();
}

6. Также, затупы я испытывал и при изучении dll:

6.1 UiTest\Scripts\Cheats.cs

Camera worldCamera = GameObject.Find("UICanvas").GetComponent<Canvas>().worldCamera;

Метод GameObject.Find ненадёжный. Геймдизайнер может случайно переименовать имя GameObject, тогда поиск не найдёт ничего. Лучше искать хотя бы по типу: FindObjectOfType.

6.2 Это ещё ненадёжнее: сломается также если кто-то передвинет объекты в иерархии

public List<GameObject> FindTree( )
{
    return ( from tree in GameObject.Find( "trees" ).GetComponentsInChildren<TreeContainer>() select tree.gameObject ).ToList<GameObject>();
}

outro

Всё это замедляет, и вынуждает нырять в кишки фреймворка.

Я привык писать тесты с Unity Test Framework, в отдельной .asmdef, но в том же проекте где и код игры. Когда сразу виден тестируемый код, то в тестах можно и переиспользовать некоторые DTO и типы с логикой, а также сразу можно проверить написанный тест на:

  1. ложноПоложительность: тест должен стать красным, если логика сломалась в сути.
  2. ложноОтрицательность: тест НЕ должен стать красным, если логика по сути не ломалась, если вносились косметические изменения. Т.е. после написания теста внести изменения в рабочий код, проверить поведение теста, и откатить изменения в рабочем коде. В предоставленном мне фреймворке код тестов отделён от кода проекта, что замедляет изучение.

Приятнее когда фреймворк именно помогает писать, а не загадывает загадки. Например, даёт удобный синтаксис утверждений по типу

  • exampleObject.Value.Should().Be(20);
  • Assert.AreEqual( 1, someArr.Length );

В предложенном фреймворке я таких методов для assert не уведел.

Я всё ещё готов к лайвкодингу. Но если там снова будет задача по этому фреймворку, то у меня все эти вопросы останутся. Я уверен, фреймворк может выполнять свои задачи. Но для тестового задания он выглядит грубовато. У не знакомого с этим кодом человека уйдёт на вкат в технологию слишком много времени и будет много вопросов. Вместо тестового будет "борьба с фреймворком".

Будет отлично, если засчитаете это review фреймворка как выполненное в таком необычном формате тестовое.

About

Моё Review тестового на позицию AQA в Кефир

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors