
## Verificação e Validação de Software
### Professor:
José Campos
### Alunos:
João Lopes nº55812
Filipe Martins nº55814
# Assignment #4
Este assignment passa pela realização de testes através da técnica *Model-based Testing*.
O *Model-based Testing* é uma técnica de testes *Black-box* e tem como intuito utilizar modelos de modo a realizar os testes ao sistema, um modelo é uma descrição do comportamento de um sistema, que pode ser descrito em termos de sequências de entrada, acções, condições, saída e fluxo de dados de entrada para saída.
O projeto JPass é uma aplicação *desktop* que visa apresentar uma forma simples e portátil com a qual um utilizador consegue fazer a gestão das suas palavras-passes. Juntamente com as palavras-passes guardadas é possível associar as mesmas a um nome e um URL entre muitas outras opções.
De modo a realizar os testes definidos foi utilizada a ferramenta QF-Test, que permite automatizar a realização de testes para para todo o tipo de aplicações Java, Web e Windows.
## Model-based Testing
Para que consigamos realizar *model-based testing* sobre os *use cases* escolhidos é necessário previamente definir os modelos dos mesmos, para tal precisamos de criar uma *state machine*, uma *transition tree* e uma *transition table*.
#### State machine
Começando pela *state machine*, esta é um modelo de comportamento que consiste num número finito de estados. Com base no estado atual e dado um determinado input, a máquina executa transições de estado e produz um dado output.
#### Transition tree
Como existe a possibilidade de um *use case* conter diversos caminhos possíveis de executá-lo, é necessária a criação de uma *transition tree*, onde, através de um grafo, conseguimos expor esses caminhos, definindo por quais estados estes passam. Desta forma conseguimos ter uma visão mais ampla do use case e também conseguimos escolher qual o caminho a testar.
#### Transition table
Por fim uma *transition table* é uma versão tabular de uma *state machine* e permite-nos identificar para que estado nos vamos mudar com base no evento executado. Através desta tabela conseguimos identificar também os *sneak paths*, que são caminhos que não estão especificados e que não deveriam ser possíveis de executar.
## Use Case 1 - Add new entry
#### Descrição do Use Case e motivo da escolha.
O use case passa por criar uma nova *entry* no ficheiro, para tal é necessário colocar um título, um URL (para associar a uma palavra-passe), um user name e por fim a palavra-passe, esta pode ser colocada manualmente pelo utilizador ou gerada automaticamente, seguindo algumas regras estabelecidas pelo mesmo. É ainda possível adicionar uma nota à *entry*.
No fim, a *entry* é adicionada ao ficheiro que o utilizador está a utilizar.
A escolha deste use case deve-se ao facto de este ser uma funcionalidade core da aplicação jPass.
#### State machine
Após a realização do *state machine* conseguimos identificar quais os estados do *use case* e também quais os eventos que ocorrem. Em relação aos estados, foram identificados cinco estados, sendo três estados normais e dois estados de erro. Passando para os eventos, estes são sete, onde quatro são eventos normais e três são eventos que têm condições.
* Estados:
* Dashboard.
* New Entry.
* Generate Password.
* Estados de erro:
* New Entry Error Popup.
* Generate Password Error Popup.
* Eventos:
* Add new entry.
* Cancel.
* Close.
* Generate new password.
* Eventos com condição:
* Confirm new entry [Title != null].
* Accept generate password [password_valid == true].
* Accept generate password [password_valid == false].

#### Transition tree
Utilizando a *transition tree* deste *use case* podemos observar que existem quatro caminhos possíveis de executá-lo, sendo o mais simples o que passa por apenas três estados, e o mais complexo passa por seis.
1. Dasboard 0 → New Entry → Dashboard 1. (Caminho mais curto);
2. Dasboard 0 → New Entry → Generate Password 0 → Generate Password Error Popup → Generate Password 1 → ... (Caminho mais longo);
3. Dasboard 0 → New Entry → New Entry Error Popup → New Entry 2 → ...;
4. Dasboard 0 → New Entry → Generate Password 0 → New Entry 1 → Dashboard 2;

#### Transition table
Para este use case conseguimos identificar vinte e três *sneak paths*, tendo estes de ser testados de modo a confirmar que o sistema não tem um comportamento invulgar.

Após a definição dos modelos, chegamos à parte de criar os testes, para tal iremos criar testes que cubram todos os estados e transições que foram definidas.
De modo a conseguirmos cobrir todos os estados e transições teremos de testar todos os caminhos, visto ser a única maneira de cobrir totalmente os modelos definidos.
Assim definidos os seguintes testes:
1. **Adicionar uma nova *entry* sem qualquer erro e com uma palavra-passe inserida manualmente**, para tal teremos de preencher todos os campos requeridos (Title,URL,User name,Password,Repeat), os valores colocados nos mesmos não são relevantes tendo sido utilizados para este teste os seguintes:
* Title: title
* URL: url
* User name: user
* Password: pass
* Repeat: pass
Através deste teste conseguimos analisar dois estados e duas transições.
2. **Adicionar uma nova *entry* sem qualquer erro e com uma palavra-passe inserida automaticamente**, sendo necessário preencher todos os campos menos os relativos à palavra-passe (Title,URL,User name). De modo a gerar a palavra-passe, será necessário escolher essa opção no GUI, e de seguida escolher quais a opções pretendidas para a geração da palavra-passe. Neste caso foram utilizadas as opções pré-definidas e em relação aos restantes campos foram utilizados os mesmos do teste anterior.
Através deste teste conseguimos analisar três estados e quatro transições.
3. **Adicionar uma nova *entry* vazia acionando o pop-up de erro**, de modo a conseguirmos acionar o pop-up de erro, é necessário não preencher os campos requeridos e carregar no botão de `OK`, de seguida será acionado o pop-up de erro relativo a uma *entry* vazia.
Através deste teste conseguimos analisar três estados e três transições.
4. **Adicionar uma nova *entry* gerando uma palavra-passe e acionado o pop-up de erro**, ao invés do teste anterior o pop-up de erro será relativo a geração de uma palavra-passe. Para acionarmos este pop-up de erro não é necessário preencher nenhum dos campos requeridos, mas sim carregar no botão para gerar uma palavra-passe, e aceitar a geração vazia, de modo a acionar o pop-up de erro.
Através deste teste conseguimos analisar quatro estados e três transições.
#### Testes realizados
De modo a conseguirmos testar os testes definidos anteriormente, foi preciso criar um *test set* para o *use case*, onde foi colocado o *setup* de iniciação da aplicação, de seguida foram criados quatro *test cases*, um para cada teste definido, e criadas as *sequences* que seguiam o modelo definido, por fim foi necessário verificar se o teste tinha sido bem-sucedido, para tal utilizamos a funcionalidade *record checks*, que compara o valor obtido com o valor esperado.
No primeiro teste, que tinha como objetivo adicionar uma nova *entry* sem qualquer erro e com uma palavra-passe inserida manualmente, e que seguia o caminho 1, verificamos que a criação da *entry* foi realizada com sucesso, tendo após a criação da mesma verificado, através do *record check* que o título da *entry* inserida correspondia ao título inserido. Desta forma concluímos que o teste correu com sucesso e que este caminho tem o comportamento esperado.
No segundo teste, que tinha como objetivo adicionar uma nova *entry* sem qualquer erro e com uma palavra-passe inserida automaticamente, e que seguia o caminho 4, verificamos que a criação da *entry* foi realizada com sucesso, tal como a geração da palavra-passe, tendo após a criação da mesma verificado, através do *record check* que o título da *entry* inserida correspondia ao título inserido. Desta forma concluímos que o teste correu com sucesso e que este caminho tem o comportamento esperado.
No terceiro teste, que tinha como objetivo adicionar uma nova *entry* vazia acionando o pop-up de erro, e que seguia o caminho 3, verificamos que ao não introduzirmos nenhum valor nos campos requeridos que o pop-up de erro era acionado, onde nos indicava que seria necessário preencher os mesmos de modo a criar uma *entry*. Com uso do *record check* conseguimos verificar que após a tentativa de criação o pop-up era despoletado. Assim concluímos que o teste correu como esperado e sem comportamentos imprevistos.
Por fim no quatro teste, que tinha como objetivo adicionar uma nova *entry* gerando uma palavra-passe e acionado o pop-up de erro, e que seguia o caminho 2, verificamos que no estado de geração da palavra-passe, caso não haja nenhuma característica selecionada, ou não haja uma palavra-passe gerada, que o pop-up era acionado, informando o utilizador do mesmo. Tal como no teste anterior conseguimos verificar que o pop-up era despoletado. Desta forma conseguimos concluir que o teste foi realizado com sucesso e sem comportamentos inesperados.
## Use Case 2 - Edit new entry
O use case passa por editar uma *entry* previamente criada, para tal o utilizador tem que selecionar a *entry* de forma a poder alterar todos os campos da *entry*.
No fim, a *entry* é editada e guardada no ficheiro que o utilizador está a utilizar.
A escolha deste use case deve-se novamente ao facto de este ser uma funcionalidade core da aplicação jPass, a edição de uma *entry*, quer seja para alterar a palavra-passe ou alterar o URL associado à mesma ou um dos outros campos da *entry*.
#### Descrição do Use Case e motivo da escolha.
#### State machine
Para o segundo use case, a *state machine* não difere muito da do primeiro use case. Podemos observar que para este use case temos cinco estados, sendo dois estados de erro e os restantes normais, em relação aos eventos, são sete, tendo três condições de fluxo três e quatro eventos normais. A única diferença encontra-se nos eventos e nos estados, os quais são agora referentes a uma edição.
* Estados:
* Dashboard.
* New Entry.
* Generate Password.
* Estados de erro:
* New Entry Error Popup.
* Generate Password Error Popup.
* Eventos:
* Add new entry.
* Cancel.
* Close.
* Generate new password.
* Eventos com condição:
* Confirm new entry [Title != null].
* Accept generated password [password_valid == true].
* Accept generated password [password_valid == false].

#### Transition tree
Para a *transition tree*, acontece a mesma situação, na qual a *transition tree* é igual à que representa o primeiro use case. Desta forma os caminhos são os mesmos, podemos observar que existem quatro caminhos possíveis de executá-lo, sendo o mais simples o que passa por apenas três estados, e o mais complexo passa por seis.
Novamente a única diferença esta presente nos estados, os quais são agora referentes a uma edição.

1. Dasboard 0 → Edit entry 0 → Dashboard 1. (Caminho mais curto);
2. Dasboard 0 → Edit entry 0 → Generate Password 0 → Generate Password Error Popup → Generate Password 1 → ... (Caminho mais longo);
3. Dasboard 0 → Edit entry 0 → Edit entry Error Popup → Edit entry 2 → ...;
4. Dasboard 0 → Edit entry 0 → Generate Password 0 → Edit Entry 1 → Dashboard 2;
#### Transition table
Para a *transition table* todos os *sneak paths* são iguais ao do primeiro use case, visto que todas as ações são essencialmente as mesmas.
Como tal, conseguimos identificar vinte e três *sneak paths*, tendo estes de ser testados de modo a confirmar que o sistema não tem um comportamento invulgar.

Devido as semelhanças com o primeiro use case, os testas são também bastante semelhantes aos realizados anteriormente. Como tal através da análise deste use case conseguimos chegar a quatro testes que devemos realizar, sendo estes testes bastante semelhantes aos que foram realizados ao primeiro use case.
1. **Editar uma *entry* sem qualquer erro e com uma palavra-passe inserida manualmente**, de forma a conseguir realizar este teste teremos de preencher todos os campos requeridos (Title,URL,User name,Password,Repeat), os valores colocados nos mesmos não são relevantes tendo sido utilizados para este teste os seguintes:
* Title: title
* URL: url
* User name: user
* Password: pass
* Repeat: pass
Através deste teste conseguimos analisar dois estados e duas transições.
2. **Editar uma *entry* sem qualquer erro e com uma palavra-passe inserida automaticamente**, sendo necessário preencher todos os campos menos os relativos à palavra-passe (Title,URL,User name). De modo a gerar a palavra-passe, será necessário escolher essa opção no GUI, e de seguida escolher quais a opções pretendidas para a geração da palavra-passe. Neste caso foram utilizadas as opções pré-definidas e em relação aos restantes campos foram utilizados os mesmos do teste anterior.
Através deste teste conseguimos analisar três estados e quatro transições.
3. **Editar uma *entry* de forma a acionar um pop-up de erro**, de modo a conseguirmos acionar o pop-up de erro, é necessário não preencher os campos requeridos e carregar no botão de `OK`, de seguida será acionado o pop-up de erro relativo a uma *entry* vazia.
Através deste teste conseguimos analisar três estados e três transições.
4. **Editar uma *entry* gerando uma palavra-passe e acionado o pop-up de erro**, ao invés do teste anterior o pop-up de erro será relativo a geração de uma palavra-passe. Para acionarmos este pop-up de erro não é necessário preencher nenhum dos campos requeridos, mas sim carregar no botão para gerar uma palavra-passe, e aceitar a geração vazia, de modo a acionar o pop-up de erro.
Através deste teste conseguimos analisar quatro estados e três transições.
#### Testes realizados
De modo a conseguirmos testar os testes definidos anteriormente, foi preciso criar um *test set* para o *use case*, onde foi colocado o *setup* de iniciação da aplicação, de seguida foram criados quatro *test cases*, um para cada teste definido, e criadas as *sequences* que seguiam o modelo definido, por fim foi necessário verificar se o teste tinha sido bem-sucedido, para tal utilizamos a funcionalidade *record checks*, que compara o valor obtido com o valor esperado.
No primeiro teste, que tinha como objetivo editar uma *entry* que tenha sido selecionada sem qualquer erro e com uma palavra-passe inserida manualmente, e que seguia o caminho 1, verificamos que a edição de uma da *entry* foi realizada com sucesso, tendo após a edição da mesma verificado, através do *record check* que o título da *entry* inserida correspondia ao título inserido. Desta forma concluímos que o teste correu com sucesso e que este caminho tem o comportamento esperado.
No segundo teste, que tinha como objetivo editar uma *entry* que tenha sido selecionada sem qualquer erro e com uma palavra-passe inserida automaticamente, e que seguia o caminho 4, verificamos que a edição da *entry* foi realizada com sucesso, tal como a geração da palavra-passe, tendo após a edição da mesma verificado, através do *record check* que o título da *entry* inserida correspondia ao título inserido. Desta forma concluímos que o teste correu com sucesso e que este caminho tem o comportamento esperado.
No terceiro teste, que tinha como objetivo editar *entry* que tenha sido selecionada vazia acionando o pop-up de erro, e que seguia o caminho 3, verificamos que ao não introduzirmos nenhum valor nos campos requeridos que o pop-up de erro era acionado, onde nos indicava que seria necessário preencher os mesmos de modo a editar uma *entry*. Com uso do *record check* conseguimos verificar que após a tentativa de edição o pop-up era despoletado. Assim concluímos que o teste correu como esperado e sem comportamentos imprevistos.
Por fim no quatro teste, que tinha como objetivo editar uma *entry* que tenha sido selecionada gerando uma palavra-passe e acionado o pop-up de erro, e que seguia o caminho 2, verificamos que no estado de geração da palavra-passe, caso não haja nenhuma característica selecionada, ou não haja uma palavra-passe gerada, que o pop-up era acionado, informando o utilizador do mesmo. Tal como no teste anterior conseguimos verificar que o pop-up era despoletado. Desta forma conseguimos concluir que o teste foi realizado com sucesso e sem comportamentos inesperados.
## Use Case 3 - Save File
O *use case* passa por salvar o ficheiro no sistema do utilizador, para tal o utilizador tem de definir o nome e local onde pretende que o ficheiro seja guardado, será neste ficheiro que serão guardadas todas as *entries* que o utilizador criou. Após a seleção do nome, o utilizador terá de indicar uma palavra-passe de modo a bloquear o acesso a outras pessoas.
No fim, o utilizador fica com um ficheiro no seu sistema.
A escolha deste use case deve-se ao facto de este ser uma funcionalidade bastante útil, conseguir exportar este tipo de ficheiro irá ajudar na portabilidade da aplicação.
#### State machine
Para o terceiro use case com a construção da *state machine* conseguimos identificar cinco estados, dos quais três estados normais e um estado de erro. Passando para os eventos, estes são seis, onde três são eventos normais e três são eventos que têm condicões.
* Estados:
* Dashboard.
* Save File.
* Enter password.
* Estados de erro:
* Enter password Error Popup.
* Eventos:
* Cancel.
* Choose name.
* Close.
* Eventos com condição:
* Confirm new entry [Title != null].
* Accept generated password [password_valid == true].
* Accept generated password [password_valid == false].

#### Transition tree
Para a *transition tree*, e devido a simplicidade que é o terceiro use case, esta *transition tree* é a mais simples e pequena com apenas três caminhos. Sendo o mais simples o que passa por apenas dois estados, enquanto o mais complexo passa por seis.
Novamente a única diferença esta presente nos estados, os quais são agora referentes a uma edição.

1. Dasboard 0 → Dashboard 1 (Caminho mais curto);
2. Dasboard 0 → Save file → Enter Password 0 → Enter password Error popup → Enter Password 1 → ... .
3. Dasboard 0 → Save file → Enter Password 0 → DashBoard 1;
#### Transition table
Para o terceiro use case foi possível identificar dezoito *sneak paths*, como tal existem dezoito cenários a ser testados para garantir que o sistema tem o comportamento esperado.

Depois da análise realizada conseguimos chegar ao um conjunto de testes que devemos realizar, estes testes têm por base os vários modelos realizados.
Como tal para o terceiro use case temos 3 testes.
1. **Guardar um ficheiro com a palavra-passe correta**, para se conseguir realizar este teste, teremos que guardar um ficheiro e preencher o campo da palavra-passe de forma correta. A aplicação irá pedir uma palavra-passe, sendo que esta terá que ser colocada por 2 vezes, de forma a evitar possíveis equívocos. A palavra-passe a ser utilizada será:
* Palavra-passe: pass
* Palavra-passe repetida: pass
Através deste teste conseguimos analisar quatro estados e três transições.
2. **Guardar um ficheiro com a palavra-passe incorreta**, para se conseguir realizar este teste, teremos que guardar um ficheiro e preencher o campo da palavra-passe de forma incorreta. A aplicação irá pedir uma palavra-passe, sendo que esta terá que ser colocada por 2 vezes, de forma a evitar possíveis equívocos. A palavra-passe a ser utilizada será:
* Palavra-passe: palavra
* Palavra-passe repetida: pass
Através deste teste conseguimos analisar seis estados e cinco transições.
3. **Guardar um ficheiro já existente**, para se conseguir realizar este teste, teremos que guardar um ficheiro já existente. A aplicação irá proceder ao guardar do ficheiro sem pedir que seja colocada uma palavra-passe.
Através deste teste conseguimos analisar um estado e uma transição.
#### Testes realizados
De forma a conseguir realizar os testes acima descritos, inicialmente temos que criar um *test set*, onde foram criados todos os passos anteriores ao teste. Seguidamente para cada um dos testes foram criadas as *sequences* necessárias. Por fim, o objetivo passa por correr os testes e verificar se o resultado é o esperado ou não, utilizando a ferramenta *record checks*.
Para o primeiro teste, para o qual o objetivo é guardar um ficheiro com a palavra-passe correta, este teste corresponde ao caminho 1. Para esta situação podemos verificar que ao tentar guardar um ficheiro com uma palavra-passe correta, a aplicação guardava o ficheiro e reencaminhava o utilizador para o dashboard.
Com a utilização do *record check* conseguimos confirmar o que era esperado, que o nome da página tinha agora o nome que foi dado ao ficheiro. Assim concluímos que o teste correu como esperado e sem comportamentos imprevistos.
Para o segundo teste, para o qual o objetivo é guardar um ficheiro com a palavra-passe incorreta e acionar um pop-up de erro, este teste corresponde ao caminho 2. Nesta situação podemos verificar que ao tentar guardar um ficheiro com uma palavra-passe errada era levantado um erro que indicava que a palavra-passe estava incorreta.
Com a utilização do *record check* conseguimos confirmar o que era esperado, ao tentar guardar um ficheiro utilizando uma palavra-passe errada, um pop-up é despoletado. Assim concluímos que o teste correu como esperado e sem comportamentos imprevistos.
Para o terceiro e último teste, o objetivo é simplesmente guardar um ficheiro que está a ser utilizado e que já exista no sistema. Para esta situação, o objetivo é apenas guardar um ficheiro que esteja a ser utilizado.
Com a utilização do *record check* conseguimos confirmar o que era esperado. Assim concluímos que o teste correu como esperado e sem comportamentos imprevistos.
#### Sneak Paths
Por fim foi necessário, dos inúmeros *sneak paths* existentes nos três *use cases*, testar três. Para tal retiramos um de cada *use case*:
1. Referente ao primeiro *use case*, temos o *sneak path* onde estamos no estado *New Entry* e tentamos aceitar uma palavra-passe gerada, ou seja, tentamos ativar o evento *Accept generated password [password_valid == false]*. A previsão deste teste é que não seria possível ativar o evento desejado e o programa deveria continuar o seu comportamento, neste caso deveria se manter no ecrã de criação de uma *entry*. Após a criação do teste conseguimos comprovar a nossa previsão, não só não permitiu que o evento fosse ativado, como não mudou o ecrã que estava a ser mostrada ao utilizador.
2. Passando para o segundo *use case*, o *sneak path* escolhido foi editar uma *entry*, gerar uma nova palavra-passe, e a partir deste ecrã abrir novamente o ecrã de editar uma *entry*, na teoria esta ação não é permitida, sendo que o ecrã de editar uma *entry* não deve ser aberto. Com a realização do teste, podemos comprovar o que foi previsto, sendo que aquando da tentativa de ativar o evento de editar uma *entry*, o programa não o permitiu, tendo se mantido no ecrã de geração da palavra-passe.
3. Por fim, para o terceiro *use case*, o *sneak path* utilizado foi guardar um ficheiro, abrir o pop-up relativo a palavra-passe, e tentar novamente abrir o ecrã para guardar o ficheiro. Foi previsto que o programa não deveria deixar que o mesmo sucedesse, e que o programa deveria manter o ecrã onde se encontrava. Depois de realizado o teste, podemos comprovar o que tinha sido previsto, ou seja, o programa não teve um comportamento invulgar, e manteve o seu estado atual.
## Opinion on the QF-Test tool
Regarding the QF-Test tool, we found that are 2 major point that make it a useful working tool and one that works against it.
First off, we really like how easy it is to use and configure, this together with so many functionalities make this software worth trying and using.
We found however that the user interface is indeed outdated, we also felt that due to the interface, the immediate response while using the QF is that "is it really worth using?" or should we search for a different option.
Overall, we give this tool a very positive feedback.