UIAutomator рдХреЗ рд╕рд╛рде рд╕реНрд╡рдЪрд╛рд▓рд┐рдд Android рдкрд░реАрдХреНрд╖рдг рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░реЗрдВ


рдлреЛрдЯреЛ рд╕реНрд░реЛрдд
рдЕрдиреБрдкреНрд░рдпреЛрдЧ рд╡рд┐рдХрд╛рд╕ рдХреЗ рджреМрд░рд╛рди рдкрд░реАрдХреНрд╖рдг рдПрдХ рдмрд╣реБрдд рдорд╣рддреНрд╡рдкреВрд░реНрдг рдкреНрд░рдХреНрд░рд┐рдпрд╛ рд╣реИред рдПрдВрдбреНрд░реЙрдЗрдб рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рдЖрд╡реЗрджрди рдкрд░реАрдХреНрд╖рдг рдХреЛ рдмрдбрд╝реА рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдЙрдкрдХрд░рдгреЛрдВ рдкрд░ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП, рдЗрд╕ рддрдереНрдп рдХреЗ рдХрд╛рд░рдг рдХрд┐ рдЙрдирдореЗрдВ рд╕реЗ рдХрдИ рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ (рд╕реНрдХреНрд░реАрди рд░рд┐рдЬрд╝реЙрд▓реНрдпреВрд╢рди, рдПрдВрдбреНрд░реЙрдЗрдб рд╡рд░реНрдЬрди, рдЖрджрд┐) рдореЗрдВ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдЕрдВрддрд░ рд╣реИрдВред рдмрдбрд╝реА рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдЙрдкрдХрд░рдгреЛрдВ рдкрд░ рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рдПрдХ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░рдиреЗ рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рд╕рдордп рд▓реЗрдиреЗ рд╡рд╛рд▓реА, рдердХрд╛рдК рдФрд░ рддреНрд░реБрдЯрд┐ рдкреНрд░рд╡рдг рд╣реЛ рд╕рдХрддреА рд╣реИред рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдкрд░реАрдХреНрд╖рдг рдХреЛ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЕрдзрд┐рдХ рдХреБрд╢рд▓ рдФрд░ рд╡рд┐рд╢реНрд╡рд╕рдиреАрдп рджреГрд╖реНрдЯрд┐рдХреЛрдг рд╣реИред UIAutomator рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ, рдЖрдк рдПрдХ рдкрд░реАрдХреНрд╖рдг рд╕реНрдХреНрд░рд┐рдкреНрдЯ рд╡рд┐рдХрд╕рд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдЬреЛ рдХрдИ Android рдЙрдкрдХрд░рдгреЛрдВ рдкрд░ рдХрд╛рдо рдХрд░реЗрдЧреА
рдПрдХ рд╣реА рд╕рдЯреАрдХрддрд╛ рдФрд░ reproducibility рдХреЗ рд╕рд╛рдеред

UIAutomator


UIAutomator Google рджреНрд╡рд╛рд░рд╛ рд╡рд┐рдХрд╕рд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ рдФрд░ Android SDK рдХреЗ рд╕рд╛рде рдЬрд╣рд╛рдЬ рд╣реИред UIAutomator Android рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдХреЗ рдкрд░реАрдХреНрд╖рдг рдХреЗ рд▓рд┐рдП Apple рдХреЗ UIAutomation рдЙрдкрдХрд░рдг рдХрд╛ рдПрдХ рдПрдирд╛рд▓реЙрдЧ рд╣реИред рдПрдВрдбреНрд░реЙрдЗрдб рдПрд╕рдбреАрдХреЗ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЗ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рдХрд╛рд░реНрдпрд╛рддреНрдордХ рдкрд░реАрдХреНрд╖рдг рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдЙрдкрдХрд░рдг рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ:


рдЗрди рдЙрдкрдХрд░рдгреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ Android рд╡рд╛рддрд╛рд╡рд░рдг рдХреЗ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдШрдЯрдХреЛрдВ рдХреЛ рд╕реНрдерд╛рдкрд┐рдд рдХрд░рдирд╛ рд╣реЛрдЧрд╛:


UIAutomator рдХреЛ рд▓рдЧрд╛рддрд╛рд░ рдЕрдкрдбреЗрдЯ рдХрд┐рдпрд╛ рдЬрд╛ рд░рд╣рд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдирд╡реАрдирддрдо рджрд╕реНрддрд╛рд╡реЗрдЬрд╝ рд╡реЗрдмрд╕рд╛рдЗрдЯ рдкрд░ рджреЗрдЦреЗ рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВ: http://developer.android.com/tools/help/uiautomator/index.html ред

рдкрд░реАрдХреНрд╖рдг рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП UIAutomator рдХреЗ рд▓рд╛рдн:


рд▓реЗрдХрд┐рди рдЗрд╕рдХреЗ рдиреБрдХрд╕рд╛рди рднреА рд╣реИрдВ:


UIAutomator рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХрд┐рд╕реА рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░рдирд╛ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдЪрд░рдгреЛрдВ рдореЗрдВ рд╢рд╛рдорд┐рд▓ рд╣реИ:

  1. рдкрд░реАрдХреНрд╖рдг рдХреА рддреИрдпрд╛рд░реА: рдбрд┐рд╡рд╛рдЗрд╕ рдкрд░ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдЗрдВрд╕реНрдЯреЙрд▓ рдХрд░рдирд╛, рдЗрд╕рдХреЗ рдпреВрдЖрдИ рдШрдЯрдХ рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░рдирд╛;
  2. рдЖрд╡реЗрджрди рдХреЗ рд▓рд┐рдП рдПрдХ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рдкрд░реАрдХреНрд╖рдг рдмрдирд╛рдирд╛;
  3. рдПрдХ рдЬрд╛рд░ рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдкрд░реАрдХреНрд╖рдг рдХреЛ рд╕рдВрдХрд▓рд┐рдд рдХрд░рдирд╛ рдФрд░ рдЗрд╕реЗ рдбрд┐рд╡рд╛рдЗрд╕ рдкрд░ рдХреЙрдкреА рдХрд░рдирд╛;
  4. рдкрд░реАрдХреНрд╖рдг рдЪрд▓рд╛рдПрдВ рдФрд░ рдкрд░рд┐рдгрд╛рдореЛрдВ рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░реЗрдВ;
  5. рдкрд░реАрдХреНрд╖рдг рдХреЗ рджреМрд░рд╛рди рдорд┐рд▓реА рд╡рд┐рднрд┐рдиреНрди рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХрд╛ рд╕реБрдзрд╛рд░ред

рд▓рд┐рдкрд┐ рд╡рд┐рдХрд╛рд╕


UIAutomator рдкреНрд░реМрджреНрдпреЛрдЧрд┐рдХрд┐рдпреЛрдВ рдХреЗ рд╕рд╛рде рдЦреБрдж рдХреЛ рдкрд░рд┐рдЪрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдПрдХ рд╕рд░рд▓ рдХрд╛рд░реНрдпрдХреНрд░рдо рдиреАрдЪреЗ рдкреНрд░рд╕реНрддреБрдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ рдЬреЛ рдбрд┐рд╡рд╛рдЗрд╕ рдХреЗ рд╕рд╛рде рд╕рд░рд▓ рдХреНрд░рд┐рдпрд╛ рдХрд░рддрд╛ рд╣реИред рдПрдХ рдорд╛рдирдХ рдПрдВрдбреНрд░реЙрдЗрдб рдПрдкреНрд▓рд┐рдХреЗрд╢рди, рдореИрд╕реЗрдЬрд┐рдВрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдкрд░реАрдХреНрд╖рдг рдХрд┐рдП рдЧрдП рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рд░реВрдк рдореЗрдВ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛, рдФрд░ рдпреВрдЖрдИрдпреВрдЯреЛрдореЗрдЯрд░ рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдирдВрдмрд░ рдкрд░ рдПрдХ рдПрд╕рдПрдордПрд╕ рд╕рдВрджреЗрд╢ рднреЗрдЬреЗрдЧрд╛ред

рдкрд░реАрдХреНрд╖рдг рдореЗрдВ рд▓рд╛рдЧреВ рд╣реЛрдиреЗ рд╡рд╛рд▓реА рдХреНрд░рд┐рдпрд╛рдУрдВ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░реЗрдВ:

  1. рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдЦреЛрдЬреЗрдВ рдФрд░ рд▓реЙрдиреНрдЪ рдХрд░реЗрдВ;
  2. рдПрдХ рд╕рдВрджреЗрд╢ рдмрдирд╛рдПрдВ рдФрд░ рднреЗрдЬреЗрдВред

рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рд╕рдм рдХреБрдЫ рдХрд╛рдлреА рд╕рд░рд▓ рд╣реИред

рдЯреЗрд╕реНрдЯ рдХреА рддреИрдпрд╛рд░реА


UIAutomatorviewer рдХрд╛ рдЙрдкрдпреЛрдЧ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред UIAutomatorviewer рдбрд┐рд╡рд╛рдЗрд╕ рдХрд╛ рдПрдХ рд╕реНрдХреНрд░реАрдирд╢реЙрдЯ рд▓реЗрддрд╛ рд╣реИ рдЬреЛ рдХрдВрдкреНрдпреВрдЯрд░ рд╕реЗ рдЬреБрдбрд╝рд╛ рд╣реЛрддрд╛ рд╣реИ, рдФрд░ рдкрд░рддреЛрдВ рдХреА рдкрджрд╛рдиреБрдХреНрд░рдо рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдФрд░ рдкреНрд░рддреНрдпреЗрдХ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдШрдЯрдХ рдХреЗ рдЧреБрдгреЛрдВ рдХреЛ рд╡реНрдпрдХреНрддрд┐рдЧрдд рд░реВрдк рд╕реЗ рджреЗрдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рдЪрд┐рддреНрд░рдордп рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рднреА рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред рдЗрд╕ рдЬрд╛рдирдХрд╛рд░реА рдХреЗ рд╣реЛрдиреЗ рд╕реЗ UIAutomator рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдмрдирд╛рдиреЗ рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХрд╛рдлреА рд╕рд░рд▓ рд╣реЛ рдЬрд╛рддреА рд╣реИред

рдЫрд╡рд┐

рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП:


рдпрджрд┐ UIAutomatorviewer рдЫрд╡рд┐ рдХреЛ рдШрдЯрдХреЛрдВ рдореЗрдВ рд╡рд┐рдШрдЯрд┐рдд рдирд╣реАрдВ рдХрд░ рд╕рдХрддрд╛ рд╣реИ, рддреЛ HTML 5 рдпрд╛ OpenGL рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЖрд╡реЗрджрди рд▓рд┐рдЦрд╛ рдЬрд╛рддрд╛ рд╣реИред

рд╡рд┐рдХрд╛рд╕ рдХрд╛ рдорд╛рд╣реМрд▓ рдмрдирд╛рдирд╛


рдпрджрд┐ рдЖрдк рдЧреНрд░рд╣рдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣реЗ рд╣реИрдВ:


рдпрджрд┐ рдПрдХ рдЕрд▓рдЧ рд╡рд┐рдХрд╛рд╕ рд╡рд╛рддрд╛рд╡рд░рдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣реЗ рд╣реИрдВ, рддреЛ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░реЗрдВ рдХрд┐ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдореЗрдВ UIAutomator.jar рдФрд░ android.jar рдлрд╛рдЗрд▓реЗрдВ рдЬреЛрдбрд╝реА рдЧрдИ рд╣реИрдВред

UIAutomator API


UIAutomator рдкрд░реАрдХреНрд╖рдг рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рднреА рд╕рдВрднрд╛рд╡рдирд╛рдУрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╛рдлреА рд╕рдордп рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреАред рд╕рднреА рд╡рд┐рд╕реНрддреГрдд рдЬрд╛рдирдХрд╛рд░реА рд╡реЗрдмрд╕рд╛рдЗрдЯ рдкрд░ рджреЗрдЦреА рдЬрд╛ рд╕рдХрддреА рд╣реИ: http://developer.android.com/tools/help/UIAutomator@india.html

рд▓рд┐рдкрд┐ рдирд┐рд░реНрдорд╛рдг


рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ рдЖрдкрдХреЛ SendMessage рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдореЗрдВ Java рд╡рд░реНрдЧ рдХреЗ рд╕рд╛рде рдПрдХ рдирдИ рдлрд╝рд╛рдЗрд▓ рдмрдирд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, SendMessage рдирд╛рдо рдХреЗ рддрд╣рддред рдпрд╣ рд╡рд░реНрдЧ UIAutomatorTestCase рд╡рд░реНрдЧ рд╕реЗ рд╡рд┐рд░рд╛рд╕рдд рдореЗрдВ рдорд┐рд▓рд╛ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред рдЧреНрд░рд╣рдг рдореЗрдВ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП, рдмрд╕ рдХреАрдмреЛрд░реНрдб рд╢реЙрд░реНрдЯрдХрдЯ Ctrl + Shift + o рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВред рдЕрдиреНрдп рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдХреЛ рдЙрд╕реА рддрд░рд╣ рд╕реЗ рдЬреЛрдбрд╝рд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдореИрдВ рдЕрдм рдЗрд╕ рдкрд░ рдзреНрдпрд╛рди рдХреЗрдВрджреНрд░рд┐рдд рдирд╣реАрдВ рдХрд░реВрдВрдЧрд╛ред

рд╣рдо рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреА рдореБрдЦреНрдп рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдХреЗ рдкрд░реАрдХреНрд╖рдг рдХреЗ рд▓рд┐рдП рддреАрди рдХрд╛рд░реНрдп рдмрдирд╛рдПрдВрдЧреЗ:

  1. рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдЦреЛрдЬреЗрдВ рдФрд░ рд▓реЙрдиреНрдЪ рдХрд░реЗрдВ
  2. рдПрд╕рдПрдордПрд╕ рднреЗрдЬрдирд╛
  3. рдореБрдЦреНрдп рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЗрдиреВ рд╕реЗ рдмрд╛рд╣рд░ рдирд┐рдХрд▓реЗрдВ

рдкрд╣рд▓рд╛ рдлрд╝рдВрдХреНрд╢рди рдЬреЛ рдЗрди рд╕рднреА рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЛ рдЪрд▓рд╛рддрд╛ рд╣реИ, рдПрдХ рдкреНрд░рдХрд╛рд░ рдХрд╛ рдореБрдЦреНрдп рдлрд╝рдВрдХреНрд╢рди, рдЗрд╕ рддрд░рд╣ рджрд┐рдЦреЗрдЧрд╛:

 public void test() { // Here will be called for all other functions } 

рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рдЦреЛрдЬрдиреЗ рдФрд░ рд▓реЙрдиреНрдЪ рдХрд░рдиреЗ рдХрд╛ рдХрд╛рд░реНрдп


рдлрд╝рдВрдХреНрд╢рди рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХреНрд░рд┐рдпрд╛рдПрдВ рдХрд░реЗрдЧрд╛: рдореБрдЦреНрдп рдмрдЯрди рдкрд░ рдЬрд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рдореБрдЦреНрдп рдмрдЯрди рдкрд░ рдЬрд╛рдПрдВ, рдореЗрдиреВ рдЦреЛрд▓реЗрдВ рдФрд░ рд╡рд╛рдВрдЫрд┐рдд рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рд╕рд╛рде рдЖрдЗрдХрди рдвреВрдВрдвреЗрдВ, рдЗрд╕ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рд▓реЙрдиреНрдЪ рдХрд░реЗрдВред
рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдЦреЛрдЬреЗрдВ рдФрд░ рд▓реЙрдиреНрдЪ рдХрд░реЗрдВ
 private void findAndRunApp() throws UiObjectNotFoundException { // Go to main screen getUiDevice().pressHome(); // Find menu button UiObject allAppsButton = new UiObject(new UiSelector() .description("Apps")); // Click on menu button and wait new window allAppsButton.clickAndWaitForNewWindow(); // Find App tab UiObject appsTab = new UiObject(new UiSelector() .text("Apps")); // Click on app tab appsTab.click(); // Find scroll object (menu scroll) UiScrollable appViews = new UiScrollable(new UiSelector() .scrollable(true)); // Set the swiping mode to horizontal (the default is vertical) appViews.setAsHorizontalList(); // Find Messaging application UiObject settingsApp = appViews.getChildByText(new UiSelector() .className("android.widget.TextView"), "Messaging"); // Open Messaging application settingsApp.clickAndWaitForNewWindow(); // Validate that the package name is the expected one UiObject settingsValidation = new UiObject(new UiSelector() .packageName("com.android.mms")); assertTrue("Unable to detect Messaging", settingsValidation.exists()); } 


рд╕рднреА рд╡рд░реНрдЧ рдХреЗ рдирд╛рдо, рдмрдЯрди рдкрд╛рда, рдЖрджрд┐ред uiautomatorviewer рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдкреНрд░рд╛рдкреНрдд рдХрд┐рдпрд╛ рдЧрдпрд╛ред

рдПрд╕рдПрдордПрд╕ рднреЗрдЬрдирд╛


рдЗрд╕ рдлрд╝рдВрдХреНрд╢рди рдореЗрдВ, рд╣рдо рдПрдХ рдирдпрд╛ рд╕рдВрджреЗрд╢ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЦреЛрдЬрддреЗ рд╣реИрдВ рдФрд░ рдмрдЯрди рджрдмрд╛рддреЗ рд╣реИрдВ, рдлреЛрди рдирдВрдмрд░, рд╕рдВрджреЗрд╢ рдХрд╛ рдкрд╛рда рджрд░реНрдЬ рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдлрд┐рд░ рдЗрд╕реЗ рднреЗрдЬрддреЗ рд╣реИрдВред рд╕рдВрдЦреНрдпрд╛ рдФрд░ рдкрд╛рда рдлрд╝рдВрдХреНрд╢рди рддрд░реНрдХреЛрдВ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдкрд╛рд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛:
рдПрд╕рдПрдордПрд╕ рднреЗрдЬрдиреЗ рдХрд╛ рдХрд╛рд░реНрдп
 private void sendMessage(String toNumber, String text) throws UiObjectNotFoundException { // Find and click New message button UiObject newMessageButton = new UiObject(new UiSelector() .className("android.widget.TextView").description("New message")); newMessageButton.clickAndWaitForNewWindow(); // Find to box and enter the number into it UiObject toBox = new UiObject(new UiSelector() .className("android.widget.MultiAutoCompleteTextView").instance(0)); toBox.setText(toNumber); // Find text box and enter the message into it UiObject textBox = new UiObject(new UiSelector() .className("android.widget.EditText").instance(0)); textBox.setText(text); // Find send button and send message UiObject sendButton = new UiObject(new UiSelector() .className("android.widget.ImageButton").description("Send")); sendButton.click(); } 


рд╣рдо рд╕рдВрдЦреНрдпрд╛ рдХреЗ рд▓рд┐рдП рдлрд╝реАрд▓реНрдб рдФрд░ рдХрд┐рд╕реА рд╡рд┐рд╢реЗрд╖ рд╕рдВрдХреЗрдд рджреНрд╡рд╛рд░рд╛ рд╕рдВрдЪрд╛рд░ рдХреЗ рд▓рд┐рдП рдлрд╝реАрд▓реНрдб рдирд╣реАрдВ рдвреВрдБрдв рд╕рдХрддреЗ, рдХреНрдпреЛрдВрдХрд┐ рдЗрди рд░реВрдкреЛрдВ рдХрд╛ рдХреЛрдИ рдкрд╛рда рдпрд╛ рдХреЛрдИ рд╡рд┐рд╡рд░рдг рдирд╣реАрдВ рд╣реИред рдЗрд╕рд▓рд┐рдП, рд╣рдо рдЙрдиреНрд╣реЗрдВ рдЗрдВрд╕реНрдЯреЗрдВрд╕ рд╡рд┐рдзрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП рдкрд╛рддреЗ рд╣реИрдВред рдЗрд╕ рдкрджреНрдзрддрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ, рдЖрдк рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдкрджрд╛рдиреБрдХреНрд░рдо рдореЗрдВ рдЗрд╕рдХреЗ рд╕реАрд░рд┐рдпрд▓ рдирдВрдмрд░ рд╕реЗ рдПрдХ рддрддреНрд╡ рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред

рд╣рдо рдкреНрд░рд╛рдкреНрддрдХрд░реНрддрд╛ рдХреЗ рдлреЛрди рдирдВрдмрд░ рдХреЛ рдкреИрд░рд╛рдореАрдЯрд░ рдХреЗ рд╕рд╛рде-рд╕рд╛рде рд╕рдВрджреЗрд╢ рдкрд╛рда рдХреЗ рд░реВрдк рдореЗрдВ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреА рд╕рдВрднрд╛рд╡рдирд╛ рдХрд╛ рдПрд╣рд╕рд╛рд╕ рдХрд░рддреЗ рд╣реИрдВред рдкрд░реАрдХреНрд╖рдг () рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд▓рд┐рдП рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдкреИрд░рд╛рдореАрдЯрд░ рдХреЗ рдЖрд░рдВрднреАрдХрд░рдг рдХреЛ рдЬреЛрдбрд╝рдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реИ, рдЬрд┐рд╕реЗ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛-рдкрд░рд┐рднрд╛рд╖рд┐рдд рдореВрд▓реНрдпреЛрдВ рдХреЗ рд╕рд╛рде рдЕрдзрд┐рд▓реЗрдЦрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП рдпрджрд┐ рдЙрдиреНрд╣реЗрдВ рд╕рдВрдмрдВрдзрд┐рдд рдлрд╝рдВрдХреНрд╢рди рдХреЗ рддрд░реНрдХ рдХреЗ рд░реВрдк рдореЗрдВ рдкрд╛рд░рд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛:
рдкрд░реАрдХреНрд╖рдг рдореЗрдВ рдкреИрд░рд╛рдореАрдЯрд░ рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛
  // Default parameters String toNumber = "123456"; String text = "Test message"; String toParam = getParams().getString("to"); String textParam = getParams().getString("text"); if (toParam != null) { // Remove spaces toNumber = toParam.trim(); } if (textParam != null) { text = textParam.trim(); } 


рдЗрд╕ рдкреНрд░рдХрд╛рд░, рдЖрдк рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЛ рдХрдорд╛рдВрдб рд▓рд╛рдЗрди рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдкреИрд░рд╛рдореАрдЯрд░ рдкрд╛рд╕ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдпрд╣ тАУe рд╕реНрд╡рд┐рдЪ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдЗрд╕рдХреЗ рдмрд╛рдж 2 рдорд╛рди рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВ: рдкреИрд░рд╛рдореАрдЯрд░ рдирд╛рдо рдФрд░ рдореВрд▓реНрдпред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рд╕рдВрдЦреНрдпрд╛ "777777" рдХреЛ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдкреНрд░рд╛рдкреНрддрдХрд░реНрддрд╛ рдХреА рд╕рдВрдЦреНрдпрд╛ рдХреЗ рд░реВрдк рдореЗрдВ, рд╣рдо рдорд╛рдкрджрдВрдбреЛрдВ рдХреЛ рдкрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВ: -e рд╕реЗ 777777ред рдЗрди рдорд╛рдкрджрдВрдбреЛрдВ рдХреЛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╕реНрдХреНрд░рд┐рдкреНрдЯ рд╡рд┐рдзрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреА рд╣реИ: getParams ()ред

рд▓реЗрдХрд┐рди рдХрдИ рдиреБрдХрд╕рд╛рди рд╣реИрдВред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдХреБрдЫ рд╡рд░реНрдгреЛрдВ рдХреЗ рд╕рд╛рде рдкрд╛рда рдХреЛ рдкреНрд░рд╕рд╛рд░рд┐рдд рдХрд░рдирд╛ рдЕрд╕рдВрднрд╡ рд╣реИ, рдпреВрдЖрдИрдпреВрдЯреЛрдореЗрдЯрд░ рдЙрдиреНрд╣реЗрдВ (рдЕрдВрддрд░рд┐рдХреНрд╖, рдФрд░, <,>, (,), ",", рдЖрджрд┐, рд╕рд╛рде рд╣реА рдпреВрдирд┐рдХреЛрдб рд╡рд░реНрдгреЛрдВ рдХреЛ рд╕реНрд╡реАрдХрд╛рд░ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ)ред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВ рдЗрди рдкрд╛рддреНрд░реЛрдВ рдХреЛ рдмрджрд▓рдиреЗ рдХрд╛ рдкреНрд░рд╕реНрддрд╛рд╡ рдХрд░рддрд╛ рд╣реВрдВ рдЬрдм рдЙрдиреНрд╣реЗрдВ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЛ рдХреБрдЫ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЗ рд╕рд╛рде рдЖрдкреВрд░реНрддрд┐ рдХреА рдЬрд╛рддреА рд╣реИ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЗ рд╕рд╛рде рдЕрдВрддрд░рд┐рдХреНрд╖ рдХреЛ рдкреНрд░рддрд┐рд╕реНрдерд╛рдкрд┐рдд рдХрд░реЗрдВ: blogspaceblogред рдпрд╣ рддрдм рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реИ рдЬрдм рд╣рдо UIAutomator рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЛ рдЪрд▓рд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ рдЬреЛ рдЗрдирдкреБрдЯ рдорд╛рдкрджрдВрдбреЛрдВ рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░реЗрдЧрд╛ред рдЗрдирдкреБрдЯ рдкреИрд░рд╛рдореАрдЯрд░реЛрдВ рдореЗрдВ рдкрд╛рд░реНрд╕рд┐рдВрдЧ рдЬреЛрдбрд╝реЗрдВ рдФрд░ рдЗрди рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреЛ рдмрджрд▓реЗрдВ:
рд╕реНрдЯреНрд░рд┐рдВрдЧ рд░рд┐рдкреНрд▓реЗрд╕рдореЗрдВрдЯ рдХреЛрдб
  if (toParam != null) { toNumber = toParam.trim(); } if (textParam != null) { textParam = textParam.replace("blogspaceblog", " "); textParam = textParam.replace("blogamperblog", "&"); textParam = textParam.replace("bloglessblog", "<"); textParam = textParam.replace("blogmoreblog", ">"); textParam = textParam.replace("blogopenbktblog", "("); textParam = textParam.replace("blogclosebktblog", ")"); textParam = textParam.replace("blogonequoteblog", "'"); textParam = textParam.replace("blogtwicequoteblog", "\""); text = textParam.trim(); } 


рдореБрдЦреНрдп рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЗрдиреВ рд╕реЗ рдмрд╛рд╣рд░ рдирд┐рдХрд▓реЗрдВ


рдпрд╣ рдлрд╝рдВрдХреНрд╢рди рд╕рдмрд╕реЗ рд╕рд░рд▓ рд╣реИ рдЬрд┐рд╕реЗ рд╣рдордиреЗ рдкрд╣рд▓реЗ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдерд╛ред рд╡рд╣ рдПрдХ рдирдпрд╛ рд╕рдВрджреЗрд╢ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдмрдЯрди рдвреВрдВрдврдиреЗ рддрдХ рдмреИрдХ рдмрдЯрди рджрдмрд╛рддреА рд╣реИред

 private void exitToMainWindow() { // Find New message button UiObject newMessageButton = new UiObject(new UiSelector() .className("android.widget.TextView").description("New message")); // Press back button while new message button doesn't exist while(!newMessageButton.exists()) { getUiDevice().pressBack(); } } 

рдкрд░реАрдХреНрд╖рдг рд╕реЗ рд▓реЙрдЧ рдХрд╛ рд╕рдВрдЧреНрд░рд╣


рдкрд░реАрдХреНрд╖рдг рдкрд░рд┐рдгрд╛рдореЛрдВ рдХреЛ рд▓реЙрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдк рдорд╛рдирдХ Android рдмрдлрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдЗрд╕рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХреЛ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдореЗрдВ рдЬреЛрдбрд╝рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:
 import android.util.Log; 

рд╕рднреА рдЬрд╛рдирдХрд╛рд░реА рдЬреЛ рджрд┐рд▓рдЪрд╕реНрдк рд╣реИ, рд▓реЙрдЧ рдореЗрдВ рджрд░реНрдЬ рдХреА рдЬрд╛ рд╕рдХрддреА рд╣реИред рдпрд╣ рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:
 Log.i(String title, String title); 

рд▓реЙрдЧ рдХреЛ рдХрдорд╛рдВрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдбрд┐рд╡рд╛рдЗрд╕ рд╕реЗ рдкрдврд╝рд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:
 $ adb logcat 

рд▓реЙрдЧрдХреИрдЯ рдХреА рдЕрдзрд┐рдХ рдЬрд╛рдирдХрд╛рд░реА рдЖрдзрд┐рдХрд╛рд░рд┐рдХ рд╡реЗрдмрд╕рд╛рдЗрдЯ: developer.android.com/tools/help/logcat.html рдкрд░ рджреЗрдЦреА рдЬрд╛ рд╕рдХрддреА рд╣реИ

рдкрд░рд┐рдгрд╛рдо рдХреЛрдб


рдЗрд╕ рдкреНрд░рдХрд╛рд░, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХреЛрдб рд╣реИрдВ:
рдХреЛрдб рджреЗрдЦреЗрдВ
 package blog.send.message; import android.util.Log; import com.android.UIAutomator.core.UiObject; import com.android.UIAutomator.core.UiObjectNotFoundException; import com.android.UIAutomator.core.UiScrollable; import com.android.UIAutomator.core.UiSelector; import com.android.UIAutomator.testrunner.UiAutomatorTestCase; public class SendMessage extends UiAutomatorTestCase { public void test() throws UiObjectNotFoundException { // Default parameters String toNumber = "123456"; String text = "Test message"; String toParam = getParams().getString("to"); String textParam = getParams().getString("text"); if (toParam != null) { toNumber = toParam.trim(); } if (textParam != null) { textParam = textParam.replace("blogspaceblog", " "); textParam = textParam.replace("blogamperblog", "&"); textParam = textParam.replace("bloglessblog", "<"); textParam = textParam.replace("blogmoreblog", ">"); textParam = textParam.replace("blogopenbktblog", "("); textParam = textParam.replace("blogclosebktblog", ")"); textParam = textParam.replace("blogonequoteblog", "'"); textParam = textParam.replace("blogtwicequoteblog", "\""); text = textParam.trim(); } Log.i("SendMessageTest", "Start SendMessage"); findAndRunApp(); sendMessage(toNumber, text); exitToMainWindow(); Log.i("SendMessageTest", "End SendMessage"); } // Here will be called for all other functions private void findAndRunApp() throws UiObjectNotFoundException { // Go to main screen getUiDevice().pressHome(); // Find menu button UiObject allAppsButton = new UiObject(new UiSelector() .description("Apps")); // Click on menu button and wait new window allAppsButton.clickAndWaitForNewWindow(); // Find App tab UiObject appsTab = new UiObject(new UiSelector() .text("Apps")); // Click on app tab appsTab.click(); // Find scroll object (menu scroll) UiScrollable appViews = new UiScrollable(new UiSelector() .scrollable(true)); // Set the swiping mode to horizontal (the default is vertical) appViews.setAsHorizontalList(); // Find Messaging application UiObject settingsApp = appViews.getChildByText(new UiSelector() .className("android.widget.TextView"), "Messaging"); // Open Messaging application settingsApp.clickAndWaitForNewWindow(); // Validate that the package name is the expected one UiObject settingsValidation = new UiObject(new UiSelector() .packageName("com.android.mms")); assertTrue("Unable to detect Messaging", settingsValidation.exists()); } private void sendMessage(String toNumber, String text) throws UiObjectNotFoundException { // Find and click New message button UiObject newMessageButton = new UiObject(new UiSelector() .className("android.widget.TextView").description("New message")); newMessageButton.clickAndWaitForNewWindow(); // Find to box and enter the number into it UiObject toBox = new UiObject(new UiSelector() .className("android.widget.MultiAutoCompleteTextView").instance(0)); toBox.setText(toNumber); // Find text box and enter the message into it UiObject textBox = new UiObject(new UiSelector() .className("android.widget.EditText").instance(0)); textBox.setText(text); // Find send button and send message UiObject sendButton = new UiObject(new UiSelector() .className("android.widget.ImageButton").description("Send")); sendButton.click(); } private void exitToMainWindow() { // Find New message button UiObject newMessageButton = new UiObject(new UiSelector() .className("android.widget.TextView").description("New message")); // Press back button while new message button doesn't exist while(!newMessageButton.exists()) { getUiDevice().pressBack(); sleep(500); } } } 


UIAutomator рдкрд░реАрдХреНрд╖рдг рдХреЛ рд╕рдВрдХрд▓рд┐рдд рдФрд░ рдЪрд▓рд╛рдирд╛


  1. рдкрд░реАрдХреНрд╖рдг рдмрд┐рд▓реНрдб рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдлрд╝рд╛рдЗрд▓ рдЬрдирд░реЗрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдЯрд░реНрдорд┐рдирд▓ рдореЗрдВ рдирд┐рдореНрди рдХрдорд╛рдВрдб рдЪрд▓рд╛рдирд╛ рдЪрд╛рд╣рд┐рдП:
     $ <android-sdk>/tools/android create uitest-project -n <name> -t <target-id> -p <path> 
    - , UIAutomator ( : SendMessage), <target-id> - Android API Level ( : <android-sdk>/tools/android list targets) - .
    ANDROID_HOME:
    рдХрд╣рд╛рдВ - , UIAutomator ( : SendMessage), <target-id> - Android API Level ( : <android-sdk>/tools/android list targets) - .
    ANDROID_HOME:
    - , UIAutomator ( : SendMessage), <target-id> - Android API Level ( : <android-sdk>/tools/android list targets) - .
    ANDROID_HOME:
    • рд╡рд┐рдВрдбреЛрдЬ:
       set ANDROID_HOME=<path_to_your_sdk> 
    • рдпреВрдирд┐рдХреНрд╕:
       export ANDROID_HOME=<path_to_your_sdk> 

    рд╣рдо рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдХреЗ рд╕рд╛рде рдбрд╛рдпрд░реЗрдХреНрдЯрд░реА рдореЗрдВ рдЬрд╛рддреЗ рд╣реИрдВ, рдЬрд┐рд╕рдореЗрдВ build.xml рдлрд╝рд╛рдЗрд▓ рд╣реЛрддреА рд╣реИ рдЬреЛ рдЪрд░рдг 1 рдореЗрдВ рдЙрддреНрдкрдиреНрди рд╣реЛрддреА рд╣реИ, рдФрд░ рдХрдорд╛рдВрдб рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рддреА рд╣реИ:
     $ ant build 

    рдбрд┐рд╡рд╛рдЗрд╕ рдкрд░ рдЗрдХрдЯреНрдареЗ JAR рдлрд╝рд╛рдЗрд▓ рдХреЛ adb рдкреБрд╢ рдХрдорд╛рдВрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХреЙрдкреА рдХрд░реЗрдВ:
     $ adb push <path_to_output_jar> /data/local/tmp/ 
    рд╣рдорд╛рд░реЗ рдорд╛рдорд▓реЗ рдХреЗ рд▓рд┐рдП:
     $ adb push <project_dir>/bin/SendMessage.jar /data/local/tmp/ 

    рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдЪрд▓рд╛рдПрдБ:
     $ adb shell uiautomator runtest /data/local/tmp/SendMessage.jar тАУc blog.send.message.SendMessage -e to 777777 


    рдирд┐рд╖реНрдХрд░реНрд╖


    рдмрдбрд╝реА рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдЙрдкрдХрд░рдгреЛрдВ рдкрд░ рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВ рдХреЗ рдЙрдЪреНрдЪ рдЧреБрдгрд╡рддреНрддрд╛ рд╡рд╛рд▓реЗ рдкрд░реАрдХреНрд╖рдг рдХреЗ рд▓рд┐рдП рдпреВрдЖрдИрдпреВрдЯреЛрдореЗрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдмрд╣реБрдд рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реИред рдЗрд╕ рддрдХрдиреАрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ, рдЖрдк рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╡рд┐рднрд┐рдиреНрди рдбреЗрдореЛ рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВред

Source: https://habr.com/ru/post/In205864/


All Articles