Garantindo a Usabilidade para Todos: Testando a Acessibilidade em Aplicações Android com MockK
Tags: android, tutorial, testing, a11y
Published: 2023-02-21 18:07:43

## Intro

A acessibilidade é uma preocupação cada vez mais importante no desenvolvimento de sistemas e aplicativos para celular. Com a crescente conscientização sobre a importância da acessibilidade, é essencial garantir que todos os usuários, independentemente de suas necessidades, possam utilizar os produtos digitais de forma eficaz. Para isso, o Android disponibiliza recursos que o desenvolvedor pode utilizar para tornar as suas aplicações mais acessíveis e inclusivas.

## Objetivo

Mas quando se trata em criar testes automatizados para aplicações Android, geralmente não é uma tarefa fácil. Aqui vai um exemplo simples que baseado no guia de acessibilidade do Firebox Android e adaptado utilizando MockK.

## Fundamentos

As aplicações que ajudam na acessibilidade do Android são denominadas **AccessibilityService**. Isso significa que, se você quiser desenvolver um leitor de tela como o **Talkback**, ele precisa ser um **AccessibilityService**. Para que o **Talkback** possa ler o conteúdo exibido por um aplicativo de terceiros, ele precisa receber uma árvore hierárquica que seja basicamente uma cópia da estrutura de layout do aplicativo em questão. Em outras palavras, cada nó da árvore representa um botão ou um TextView da aplicação que será lida. Essa árvore é conhecida como **AccessibilityNodeProvider**, e os nós da árvore são denominados **AccessibilityNodeInfo**.

![Imagem que representa uma árvore de view do layout que é utilizada pelo leitor de tela. Na animação, cada nó da árvore representa uma view que dispara um evento de acessibilidade, repassa para o nó pai.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tvgciw31xrpm1cdjszhr.gif)

## Cenário

Para exemplificar, imagine uma situação onde vc tem um modal que aparece para o usuário para exibir uma mensagem. Nós queremos ter algum tipo de interação quando o usuário mudar o foco de um elemento do modal para o outro. 


![Exemplo de modal onde existem 3 itens selecionáveis e um botão para fechar o modal.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o10u05bpko6vqhhfho2z.png)


## AccessibilityDelegate

Com **AccessibilityDelegate**, é possível utilizar algumas funções para escutar determinados eventos de acessibilidade ou adicionar novas informações para a view para que sejam lidas pelo leitor de tela. O exemplo a seguir, a função **onRequestSendAccessibilityEvent** é chamada sempre que um evento de acessibilidade é disparado por uma view e com o parâmetro “event” posso verificar que tipo de evento é esse.

```kotlin
vModal.accessibilityDelegate = object : View.AccessibilityDelegate() {
    override fun onRequestSendAccessibilityEvent(
        host: ViewGroup?,
        child: View?,
        event: AccessibilityEvent?
    ): Boolean {
        if (event?.eventType==TYPE_VIEW_ACCESSIBILITY_FOCUSED){
					fazerAlgumaCoisa()
				}
        return super.onRequestSendAccessibilityEvent(host, child, event)
    }
}
```

No código a seguir, um exemplo de como podemos implementar um cenário de teste automatizado para o onRequestSendAccessibilityEvent:
```kotlin
//Mockar uma view pai
val root = mockk<ViewParent>()

//Inserir a view de teste dentro desse pai mockado
Shadows.shadowOf(vModal.view).setMyParent(root)

//Precisa garantir que haja algum retorno para esse método de acessibilidade
every{root.requestSendAccessibilityEvent(any(), any())}returns false

//Cria um shadow para simular a acessibilidade ativa
Shadows.shadowOf(BaseObject.applicationContext.getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager).setEnabled(true)

//Pega um elemento do modal
val closeButton = getCloseButton()

//Dispara um evento de foco de acessibilidade
closeButton.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED)

//Cria um slot para capturar argumento
val accessibilityEvent = slot<AccessibilityEvent>()

//Captura o argumento passado no método de acessibilidade
verify{root.requestSendAccessibilityEvent(any(), capture(accessibilityEvent))}

//Verifica se o argumento passado é o que era esperado
assertEquals(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED, accessibilityEvent.captured.eventType)
```

Este trecho de código apresenta um exemplo de como realizar um teste automatizado com foco em acessibilidade.

Inicialmente, é feita uma simulação de uma view pai, utilizando o framework **MockK**. Em seguida, a view de teste é inserida nessa view pai mockada.

Para garantir que o teste está efetivamente verificando a acessibilidade da view, é necessário que haja algum retorno para o método de acessibilidade. Assim, utilizando o framework **MockK** novamente, é definido que o retorno do método **`requestSendAccessibilityEvent`** seja falso.

Em seguida, é criado um "**shadow**" (simulação) para a acessibilidade ativa, utilizando o framework **Robolectric**. Então, é capturado um elemento do modal (provavelmente algum botão ou elemento que possa ser acessado) e é disparado um evento de foco de acessibilidade.

Com o framework **MockK**, é criado um slot para capturar o argumento passado no método de acessibilidade, que é verificado posteriormente para verificar se o argumento passado é o esperado. Por fim, é utilizada a função **`assertEquals`** para verificar se o tipo do evento de acessibilidade capturado corresponde ao tipo de evento esperado.

## Conclusão

Com isso, esse trecho de código apresenta uma forma de simular e testar a acessibilidade de uma view em um ambiente controlado, a fim de garantir uma aplicação tenha um comportamento consistente.

## Fontes
### Guia de acessibilidade do Firebox Android

[shared-docs/accessibility_guide.md at main · mozilla-mobile/shared-docs](https://github.com/mozilla-mobile/shared-docs/blob/main/android/accessibility_guide.md)

### Para adaptar o exemplo de Moquito para MockK

[`ArgumentCaptor`](https://notwoods.github.io/mockk-guidebook/docs/mockito-migrate/argument-captor/)