TALK - BATTLE
EYES OR HEART?
WHOM TO BELIEVE?
Yevhen vs Denys and Oleksii
PART 1: HEART
Automate your Unity3d
application testing with
Puppetry
Yevhen Rudiev
Yevhen Rudiev
• QA Tech Lead at TT
Soltuions
• 7 years experience in IT
• 4 years experience in
Automated Testing
• Founder of Test Unit Lab
organization
SUCCESS RELEASES
EXPENSES
REGRESSION
CLICK EVERY UI
LOCALIZATION
PLATFORMS
RESOLUTIONS
NEW RELEASE? AGAIN?
START THE AUTOMATION
TEST FRAMEWORKS
OWN FRAMEWORK
PUPPETRY
APPLICATION DRIVER
APPLICATION
DRIVER
TEST
SELENIUM FOR UNITY
SELENIUM FOR UNITY
PuppetryDriver
PUPPETRY ARCHITECTURE
Tests
Puppeteer
Unity
Puppet
Rest API Socket API
PUBLIC CLASSES
public static class PuppetryDriver
public static class Configuration
public static class Editor
public static class Game
public class GameObject
PUPPETRY DRIVER
PUPPETRY DRIVER
static void ReleaseCurrentSession()
static void ReleaseAllSession()
CONFIGURATION
CONFIGURATION
static void Set(Settings setting, object value)
public enum Settings
{
BaseUrl,
Port,
Timeout,
SessionTimeoutMs,
StartPlayModeSessionTimeoutMs,
PollingStrategy
}
EDITOR
EDITOR
void StartPlayMode();
void StopPlayMode();
GAME
GAME
void MakeScreenShot(string fullPath);
void MakeScreenShot(string fileName, string folderName)
void DeletePlayerPref(string key);
void DeleteAllPlayerPrefs();
float GetFloatPlayerPref(string key);
string GetStringPlayerPref(string key);
int GetIntPlayerPref(string key);
void SaveFloatPlayerPref(string key, float value);
void SaveStringPlayerPref(string key, string value);
void SaveIntPlayerPref(string key, int value);
bool PlayerPrefHasKey(string key);
void ExecuteCustomMethod(string method, string value = null)
GAME OBJECT
FIND GAME OBJECT
GameObject FindByName(string root, string name);
GAME OBJECT
FIND GAME OBJECT
GameObject FindByName(string root, string name);
GameObject FindByNameAndParent(
string root, string name, string parent);
GameObject FindByUpath(string upath);
UPath (Unity Path Language)
“/RootElement
/descendant::childName
//name[active]
[1]”
UPath – Type of search
- “/RootElement” – Beginning of Upath is root element
- “//{name}” – child or grandchild
- “/{name}” – direct child
- “/..” – return to parent
- “/parent::{name}” – parent
- “/ancestor::{name}” – parent or grand parent
- “/child::{name}” – child
- “/descendant::{name}” – child or grand child
- “/contains({partialName})” – partial name
UPath – Properties
- [number] – index
- [axis::{name}] – has relation according to the axis
- [active] – is active in hierarchy right now
- [!active] – is not active in hierarchy right now
SUPPORTED METHODS
void Click();
void SendKeys(string value);
void DragTo(GameObject toGameObject);
void DragTo(ScreenCoordinates toCoordinates);
void Swipe(Direction direction);
string GetComponent(string componentName);
ScreenCoordinates GetCoordinates();
int Count();
GameObject FindRelative(string upath)
VERIFICATION
bool Exist;
bool IsActiveInHierarchy;
bool IsRendering;
bool IsOnScreen;
bool IsHitByGraphicRaycast;
bool IsHitByPhysicsRaycast;
SHOULD / SHOULDNOT
gameObject.Should(Be.Present);
gameObject.ShouldNot(Be.ActiveInHierarchy);
gameObject.Should(Have.Component(“TextMeshProUGUI”));
gameObject.Should(Have.ComponentWithPropertyAndValue(
“Button",
"m_Intractable",
true.ToString().ToLower()));
HOW TO SET UP
PUPPETEER
PUPPETRY DRIVER
dotnet //PuppetryDriver/PuppetryDriver.dll
PuppetryDriver PuppetPuppeteer
PUPPET
> Unity Project
>>Assets
>>>Puppet
PuppetryDriver
Puppet
in
Unity Editor
Puppeteer
in
Tests
ORDER
TESTS
PAGE OBJECTSCREEN OBJECT
public class LoginScreen
{
GameObject nameField = new GameObject(“Canvas”, “nameField”);
GameObject passwordField =
new GameObject(“Canvas”, “passwordField”);
GameObject loginButton = new GameObject()
.FindByUpath(“/Canvas//loginForm//loginButton);
. . .
}
public MainMenuScreen MakeSuccessLogin
(string name, string password)
{
nameField.SendKeys(name);
passwordField.SendKeys(password);
loginButton.Click();
return new MainMenuScreen();
}
SCREEN OBJECT
ISOLATION OF TESTS
public static class Editor
{
public static void StartPlayMode()
public static void StopPlayMode()
}
public static class Game
{
public static void DeleteAllPrefs()
public static void DeletePref(string key)
}
TEST
[Test]
public void Login_CorrectCredentials_Success()
{
//Arrange
var name = "Yevhen";
var password = “TestingStage2019";
//Act
var screen = new LoginScreen().MakeSuccessLogin(name, password);
//Assert
Assert.IsTrue(screen.IsPageOpened,
$"Main Menu was not opened after login with {name} and {password}")
}
DEMO
TIME
SAVING RESOURCES
HEADLESS MODE
ComandLine argument: -batchmode
Example:
/Applications/Unity/Unity.app/Contents/MacOS/Unity -batchmode
https://docs.unity3d.com/Manual/CommandLineArguments.html
DEVICE TESTING
Puppet
PuppetryDriver
Puppeteer
in
Tests
MOBILE TESTING
Appium
DOCUMENTATION
CONTACTS:
www.linkedin.com/in/yevhen-rudiev-a5609590
www.facebook.com/evgeniy.rudev.5
yrudiev@gmail.com
@testunitlab
PART 2: EYES
Automation of Unity Games
with Image Recognition
Oleksii and Denys
О нас:
● Mobile AQA in Moonactive
● Master degree of system
analysis, data processing and
analysing
О нас:
● Mobile AQA in Moonactive
● 6 years as Mobile QA
● Winner of 3 Testons in IOS
Nomination
● Lector in BeQA
● Проблемы
● Решение
● Еще проблемы
● Текущее решение и то как это работает
● Куда стремимся
План:
Немного истории
Проблема 0
Unity Игры нельзя автоматизировать
классическим подходом
Варианты:
AltUnityDriver Open CV
Open CV
OpenCV (Open Source Computer Vision
Library) is released under a BSD license and
hence it’s free for both academic and
commercial use. It has C++, Python and Java
interfaces and supports Windows, Linux, Mac
OS, iOS and Android
И теперь добавили интерфейс для JS….
Как это работает?
cv.MatchTemplate(image, templ, result, method)
Parameters:
● image – Image where the search is running. It must be 8-bit or 32-bit
floating-point.
● templ – Searched template. It must be not greater than the source image
and have the same data type.
● result – Map of comparison results. It must be single-channel 32-bit floating-
point. If image is and templ is , then result is .
● method – Parameter specifying the comparison method (see below).
1. Делаем скриншот
2. Вырезаем темплейт
3. В тесте ищем
темплейт на скриншоте
с заданной точностью
И вот все круто и
мы начинаем писать тесты
Проблема 1
Разные Разрешения Экранов
Решение Проблемы
1. Делаем скриншот и ресайзим в
дефолтный размер
2. Вырезаем нужный темплейт
3. В тесте Ищем нужный темплейт на
скриншоте который ресайзим в дефолтный
размер
*this code is not used in real project
Проблема 2
UI зависит от профиля
Решение Проблемы
Async IO
*this code is not used in real project
Проблема 3
Нет возможности получить
состояние приложения
Решение Проблемы
Проблема 4
Поиск
множества
одинаковых
элементов
Решение Проблемы
k-means
Проблема 5
Разные версии элемента
Решение Проблемы
IN PROGRESS...
Куда двигаемся:
1. Нейронные Сети для Лучшего распознавания
2. Понимание Состояния приложения
Appium release
27 Aug 2018: Appium v1.9.0 added “-image” find element strategy
Available methods:
● click
● isDisplayed
● getSize
● getLocation
● getLocationInView
● getElementRect
Links:
1. Open CV - https://opencv.org
2. AltUnityDriver - https://gitlab.com/altom/altunitytester
3. AsyncIO - https://docs.python.org/3/library/asyncio.html
Контакты
https://www.linkedin.com/in/denys-iaremenko-a71346a5/
https://www.linkedin.com/in/oleksii-atamanchuk-a20686104/
https://www.facebook.com/denis.yaremenko
https://www.facebook.com/100013188274760
https://moonactive.com
https://www.linkedin.com/company/moon-active/
PART 3: BATTLE
EYES OR HEART?
WHOM TO BELIEVE?
Yevhen vs Denys and Oleksii
ROUND
1
SPEED
DRIVER
1. Start the game
2. Open Menu
3. Click “2D” button
4. Check that it contains
“Back” button
IMAGE RECOGNITION
Steps:
1. Open screen with fox
2. Check that screen is
displayed
3. Tap on button with feed
4. Tap on back button
* MacBook Pro 2.6 GHz Intel Core i7 16GB RAM
ROUND
2
STABILITY
DRIVER
gameObject.Should(Be.Present);
gameObject.Should(Be.ActiveInHierarchy);
gameObject.Should(Have.Component(“TextMeshProUGUI”));
gameObject.Should(Have.ComponentWithPropertyAndValue(
“Button",
"m_Intractable",
true.ToString().ToLower()));
IMAGE RECOGNITION
1. Searching all elements with
predefined threshold
2. Searching multiply elements
simultaneously
3. For “unstable” elements
implemented “retry”
functionality
ROUND
3
MAINTENANCE
DRIVER
GameObject nameField = new GameObject(“Canvas”, “nameField”);
GameObject passwordField = new GameObject(“Canvas”, “passwordField”);
GameObject loginButton = new GameObject()
.FindByUpath(“/Canvas//loginForm//loginButton);
IMAGE RECOGNITION
Taking
screenshot
Converting
and resizing
Move to
project
directory
Use as
selector
*this code is not used in real project
ROUND
4
THRESHOLD OF ENTRY
DRIVER
• Selenium like framework
• How to run up Puppetry
• Unity specific staff (GameObject,
Components, Unity Editor)
IMAGE RECOGNITION
• Appium knowledge base
• Check the basic methods (search and tap on
element) conception
• Devices handling procedures - searching and
set up emulators/simulators, real devices
ROUND
5
FIRST TEST
DRIVER
• Up to 30 minutes if use Puppetry or others
• Months if you want to write own
IMAGE RECOGNITION
• Up to 29 minutes
• 2-3 Weeks if you want to write your own
solution
ROUND
6
NEW TEST
DRIVER
• Declare new ScreenObjects
• Declare all GameObjects and their locators
• Describe all methods in the ScreenObject
• Write the test
IMAGE RECOGNITION
Yup, Totally the same
ROUND
7
LAYOUT TESTING
DRIVER
gameObject.Should(Be.OnScreen);
gameObject.Should(Be.HitByPhysicsRaycast);
gameObject.Should(Be.HitByGraphicRaycast);
gameObject.Should(Be.Rendered);
gameObjec.Should(Have.ComponentWithPropertyAndValue(
“Image”,
“”,
“”));
IMAGE RECOGNITION
Detecting all needed UI
elements
*this code is not used in real project
ROUND
8
LOCALIZATION TESTING
DRIVER
gameObjec.Should(Have.ComponentWithPropertyAndValue(
“TextMeshProUGUI”,
“m_Text”,
“”Bonjour””));
IMAGE RECOGNITION
• Checking any element (templates) with
localization (same as in Round 7)
ROUND
9
DIFFERENT OS
DRIVER
• Different platforms in Unity Editor
• Mobile devices (iOS, Android) with Appium
combination
• Potentially other platforms like: Xbox,
PlayStation, VR, Nintendo Switch - if you can
create Socket connection from a device
IMAGE RECOGNITION
• Mobile using appium: iOS, Android
• Almost the same for web with Selenium (with
some modifications)
• All other OS with available drivers
ROUND
10
REQUIRED ENVIRONMENT
DRIVER
• You need to have Unity Editor to start
• Appium and mobile devices / emulators to
test on devices
IMAGE RECOGNITION
• Appium
• Emulators/Simulators (Android SDK, Xcode)
ROUND
11
CI INTEGRATION
DRIVER
1. Start PuppetryDriver
2. Start Unity editor
3. Start Test
4. Kill PuppetryDriver process
5. Kill Unity editor process
IMAGE RECOGNITION
1. Install virtualenv (pipenv)
2. Start Test (appium driver starts devices
automatically)
3. Kill devices
ROUND
12
PARALLELIZATION
Unity application
Game
PARALLELIZATION
Game Game
Unity application
Game
PARALLELIZATION
Game
Unity application
DRIVER
Tests
Unity application
Unity application
Unity application
Puppetry
Driver
IMAGE RECOGNITION
Tests
Xdist
worker 1
Appium
Appium
Appium
Xdist
worker 2
Xdist
worker 3
ROUND
13
LANGUAGES SUPPORT
DRIVER
IMAGE RECOGNITION
Q&A

Eyes or heart