
O padrão Objeto de Página apareceu nos testes da Web e provou ser muito bom lá. Quando comecei a automatizar testes para aplicativos Android, a primeira coisa que pensei sobre isso. Procurei informações na rede, perguntei aos meus colegas e, em princípio, não encontrei motivos para não tentar. Proponho ver o que resultou disso.
O objeto de página clássico implica dois níveis de abstração: elementos da página e testes. Destaco mais uma - lógica de negócios. Observo que a maneira como você constrói sua estrutura afetará enormemente a facilidade de escrever testes no futuro, bem como o suporte deles. Tento fazer com que o código de teste pareça um caso de teste normal, escrito por um testador comum. I.e. Eu começo do final:
- Estou escrevendo um código de caso de teste bonito e claro,
- Eu implemento métodos do caso de teste na camada de lógica de negócios,
- Descrevo os elementos necessários para o teste.
Essa abordagem é boa porque não fazemos nada extra - a estrutura é construída o quanto for necessário para os testes funcionarem. Podemos dizer que esse é o conceito de MVP nos testes: eles rapidamente formaram uma peça e ela já começou a trazer benefícios. Se você primeiro escrever milhares de linhas, descrevendo as páginas do seu aplicativo e como interagir com elas, e depois de três meses sair do buraco para o primeiro clique e perceber que tinha que fazer tudo de maneira diferente, a maior parte da sua criação estará condenada para sempre " reunir poeira "nos porões do git ... Um verdadeiro testador sabe que quanto mais cedo um bug é encontrado, mais barato é corrigi-lo. Use essa abordagem em tudo - escreveu um teste em algumas horas, experimentou, não gostou - jogou fora, aprendeu uma lição, seguiu em frente.
Portanto, a entrada é:
- Aplicativo Android para negociação na bolsa de valores;
- Java para trabalhar na mesma pilha com desenvolvedores;
- estrutura básica UI Automator;
- você precisa escrever um teste de login no aplicativo.
Preparação do projeto
Desde que tentei integrar o máximo possível ao processo de desenvolvimento, não comecei a criar um novo projeto. De acordo com a
documentação , os testes instrumentais devem ser colocados na pasta
src/androidTest/java
. No meu caso, o coletor já foi configurado; se você tiver algo errado, leia sobre
a configuração da compilação . Também precisamos de um ambiente de desenvolvimento, Android SDK, Emulador, ferramentas, ferramentas de plataforma e as plataformas necessárias para o emulador. Se você usa o Android Studio, tudo isso pode ser instalado rapidamente através do SDK Manager:

Camada de teste
Como escrevi acima, automatizaremos o teste de login no aplicativo. Lembre-se de que o código deve se parecer com um caso de teste regular:
Pré-condição: execute o aplicativo.
Etapa 1: faça login usando a conta myLogin / myPassword.
Etapa 2: verifique o nome do usuário atual.
Resultado esperado: o usuário atual é Ivan Ivanov.
Isenção de responsabilidade pequena: de acordo com as melhores práticas do teste de design, na pré-condição em que você precisa criar / encontrar uma conta. Omiti esse momento por simplicidade de exemplo.Nossa classe ficará assim:
@RunWith(AndroidJUnit4.class) public class LoginTests { private TestApplication myApp; @Before public void setUp() { myApp = new TestApplication(); } @Test public void testLogin() { myApp.login("myLogin","myPassword"); String currentUser = myApp.getCurrentUserName(); assertEquals("Wrong name", " ", currentUser); } @After public void tearDown() { myApp.close(); } }
Lógica de negócios
O teste usa a classe
TestApplication()
e seus dois métodos:
login()
e
getCurrentUserName()
. Além disso, você precisa de um construtor de classe (iniciando o aplicativo) e do método
close()
.A frente é clara:
public class TestApplication { private UiDevice device; private PageObject page; public TestApplication() { } public void login(String login, String password) { } public String getCurrentUserName() { return "" } public void close() { } }
Uma instância da nossa classe terá duas variáveis:
device
, pertencente à classe android.support.test.uiautomator.UiDevice
- através dele, interagimos com o dispositivo;page
, a classe PageObject
, que criaremos na próxima seção.
Vamos começar com o construtor. Nele, crie instâncias de nossas variáveis e execute o aplicativo:
public TestApplication() {
Algumas dicas sobre como iniciar o aplicativoPara ter mais controle do aplicativo em teste, você pode adicionar expectativas para o iniciador (se você executar o emulador "em um frio") e o próprio aplicativo. Isso também é recomendado na
documentação .
Nota: a execução do aplicativo por android.content.Context.getTargetContext()
será adequada apenas se seus testes estiverem no mesmo projeto que o próprio aplicativo. Se separadamente, será necessário percorrer o menu.A lógica de negócios do teste são as etapas específicas que o usuário deve executar para obter qualquer resultado significativo (para o usuário). O login com seu próprio ultrassom é um resultado significativo. Etapas: clique no botão "Login", digite o nome de usuário no campo "Login", digite a senha no campo "Senha", clique no botão "Entrar". Assim, nosso método é preenchido com etapas:
public void login(String login, String password) { page.login().click(); page.loginEntry().setText(login); page.passwordEntry().setText(password); page.signIn().click(); }
Para obter o usuário atual, tudo é mais simples, basta obter o valor do campo:
public String getCurrentUserName() { return page.currentUserName().getText(); } }
E para fechar o aplicativo, basta clicar no botão Início:
public void close() { device.pressHome(); }
Descrição dos elementos da página
O conceito dessa camada é que ela retorne elementos prontos para uso (em nosso contexto, essa é a classe
android.support.test.uiautomator.UiObject2
). Ou seja, o consumidor não deve se preocupar com o estado do objeto, se ele retornar, você poderá interagir imediatamente com ele: clique, preencha ou leia o texto. Essa é uma consequência importante - nesta camada, perceberemos as expectativas:
private UiObject2 getUiObject(BySelector selector) { return device.wait(Until.findObject(selector), 10000); }
O método definido acima será usado pela interface pública da nossa classe
PageObject
. Exemplo para o campo Login:
public UiObject2 loginEntry() { return getUiObject(loginEntrySelector()); }
Resta determinar o seletor pelo qual encontraremos o campo. A instância do
android.support.test.uiautomator.BySelector
mais convenientemente obtida usando os métodos estáticos da classe
android.support.test.uiautomator.By
. Concordei com o desenvolvimento de que em todos os lugares, sempre que possível, haverá um ID de recurso exclusivo:
private BySelector loginEntrySelector() { return By.res(packageName, "login"); }
É conveniente inspecionar a interface no utilitário uiautomatorviewer incluído no pacote de ferramentas (instalado na seção Preparação):

Selecione o elemento desejado e, na seção Detalhes do nó, examinamos o ID do recurso. Consiste no nome do pacote e, de fato, no identificador. Obtivemos o nome do pacote no construtor da classe
TestApplication
e o usamos ao criar o
PageObject
.
Código completo:
classe PageObject public class PageObject { private UiDevice device; private final String packageName; private BySelector loginButtonSelector() { return By.res(packageName, "user_view"); } private BySelector loginEntrySelector() { return By.res(packageName, "login"); } private BySelector passwordEntrySelector() { return By.res(packageName, "password"); } private BySelector signInSelector() { return By.res(packageName, "btnLogin"); } private BySelector userNameSelector() { return By.res(packageName, "user_name"); } public PageObject(UiDevice device, String packageName) { this.device = device; this.packageName = packageName; } public UiObject2 login() { return getUiObject(loginButtonSelector()); } public UiObject2 loginEntry() { return getUiObject(loginEntrySelector()); } public UiObject2 passwordEntry() { return getUiObject(passwordEntrySelector()); } public UiObject2 signIn() { return getUiObject(signInSelector()); } public UiObject2 currentUserName() { return getUiObject(userNameSelector()); } private UiObject2 getUiObject(BySelector selector) { return device.wait(Until.findObject(selector), 10000); } }
Executando testes
Isso é tudo, resta correr. Primeiro, conecte-se ao dispositivo ou inicie o emulador. Verifique a conexão com o comando
adb devices
(o utilitário adb faz parte das ferramentas de plataforma):
List of devices attached emulator-5554 device
Se você tem um gradle, faça
gradlew.bat connectedAndroidTest
e aprecie como "robôs injetados, não humanos" (c).