O item de teste do Visual Studio 2010 CodedUITest é utilizado quando há a necessidade de simular a interação do usuário com um sistema. Será proposto uma forma de trabalhar quando a regra é verificar um componente e não uma informação no mapeamento da interação.
O exemplo se trata do seguinte caso de teste:
Requisito de Teste:
A aplicação é uma parte de uma tela completa onde será testado apenas o componente ListBox que exibe os últimos 10 cadastros.
O teste deve garantir que a primeira linha do ListBox foi o ultimo item a ser cadastrado no sistema.
Pré requisito do teste:
Abrir a aplicação.
Passos do teste:
1- Clicar no botão “Tela”.
2- Selecionar o ultimo cadastro que está no banco de dados.
3- Verificar se o que está na primeira linha do ListBox é o ultimo registro que foi cadastrado no banco.
Pós requisito do teste:
Fechar aplicação.
Bem vamos ao projeto de teste, para isso crie no VS2010 um projeto de teste.
[Imagem 1:Novo projeto teste]
[Imagem 2: Solution projeto teste]
Adicione um novo item ao projeto, deve ser do tipo CodedUITest.
O Visual Studio irá perguntar se deseja mapear o caminho a ser traçado pelo programa ou irá utilizar um já existente. Selecione a opção para criar um mapeamento.
[Imagem3: Gerar código de teste UI]
O aplicativo que abre é o Coded UI Builder, nele será gravado os passos executados pelo usuário e transforma em código e carrega uma classe do caminho mapeado e seus objetos.
[Imagem4: Coded UI Builder]
Vamos abrir a aplicação e gravar os passos do caso de teste (nesse exemplo é apenas um botão, mas, poderíamos ter um menu ou qualquer outro formulário)
- Clicar em Record, a partir disso será gravado as interações com o sistema
[Imagem5: Start record]
Cada interação é importante gerar o código para definir o que é cada passo.
Após executar uma etapa verificamos os passos mapeados (etapa opcional) e geramos o código, irá criar um método.
[Imagem6: Passos gravados]
[Imagem7: Criar método]
Após alguns passos executados no caso de teste está uma validação, o “Assert” realizado pelo Codo UI Builder irá definir uma propriedade de um objeto na tela que vai ser comparada.
[Imagem8: Identificando validação]
Como em nosso exemplo temos um ListBox e devo garantir que ID exibido será o ultimo ID do banco vou usar um Assert na propriedade “Name” do componente ListBoxItem. Para isso segue e arraste “o alvo” do Coded UI Builder até o componente que deseja verificar, depois, coloque a verificação em uma propriedade.
[Imagem9: Adicionar verificação]
Use o botão gerar código para criar a verificação na classe de mapeamento.
[Imagem10]
Como o leitor pode perceber até esse ponto realizamos apenas os passos 1 e 3 do caso de teste, para o passo 2 será necessário criar uma classe que vai acessar o banco de dados e trazer qual o ultimo registro que foi gravado para a comparação.
Nesse exemplo vou utilizar Linq to SLQ (poderia ser utilizado entity framework ou qualquer forma de acesso as informações) para criar o método, ficou dessa maneira:
…
public static class AcessaInfo
{
public static string codUltimoRegistro()
{
using (AcessoInfoDataContext context = new AcessoInfoDataContext())
{
System.Data.Linq.Table<LIST> tblList = context.GetTable<LIST>();
return (from reg in tblList
orderby reg.LIS_ID descending
select reg.LIS_ID).FirstOrDefault().ToString();
}
}
}
…
E o método do passo 2 fica assim, dentro da classe CodedUITest:
private void SelecionaUltimoRegistroAtribuiCampo()
{
this.UIMap.VerificaListBoxItemExpectedValues.UIItem211709201143ListItemDisplayText1 = AcessaInfo.codUltimoRegistro();
}
Existem coisas que precisam ser feitas antes de iniciar e ao finalizar o teste e isso fica definido nos métodos que estão com o atributo ‘TestInicialize’ e ‘TestCleanUp’.
Vamos preencher esses métodos com os pré-requisitos e pós-requisitos.
Para abrir e fechar a aplicação será necessário a classe ApplicationUnderTest. Ficando assim:
#region Additional test attributes
// You can use the following additional attributes as you write your tests:
ApplicationUnderTest app = new ApplicationUnderTest();
string caminhoApp = @”C:\Test\app\WinAppListBox.exe”;
////Use TestInitialize to run code before running each test
[TestInitialize()]
public void MyTestInitialize()
{
app = ApplicationUnderTest.Launch(caminhoApp);
}
////Use TestCleanup to run code after each test has run
[TestCleanup()]
public void MyTestCleanup()
{
app.Close();
}
#endregion
Agora o teste pode ser executado, para isso vamos “debugar” para verificar se está conforme o esperado.
[Imagem 11]
Problema:
O teste foi executado com sucesso, mas as validações estão como o codedUIBuilder criou e não é a validação que queremos, se for adicionado um novo registro vai continuar a buscar o registro indicado para o CodedUIBuilder.
O site MSDN.com recomenda (nas boas práticas de CodeUITest) que não altere a classe de mapeamento, mas o que foi criado não é o que o meu teste precisa.
Esse problema eu consegui resolver com o método GetChildren() da classe UIControl. Resgatando todos os “filhos” do componente ListBox e retornando o primeiro que seja ListBoxItem. Também pode servir de solução para outros componentes como GroupBox.
Fui até o método do mapeamento e verifiquei qual classe está sendo buscada, veja o caminho que foi feito pelo CodedUIBuilder:
WinListItem uIItem211709201143ListItem = this.UIJanelaExemploListBoxWindow.UILbxUltimosWindow.UIItem211709201143ListItem;
Na definição da classe do item foi verificado que o critério de pesquisa está fixo no código que vai ser tal ID.
[Imagem 12]
Nessa definição do item que vamos corrigir com o GetChildren()
No meu caso tive que buscar primeiro o WinList e nele buscar pelo primeiro componente WinListItem
public WinListItem UIItem211709201143ListItem
{
get
{
if ((this.mUIItem211709201143ListItem == null))
{
this.mUIItem211709201143ListItem = new WinListItem(this);
#region Search Criteria
//this.mUIItem211709201143ListItem.SearchProperties[WinListItem.PropertyNames.Name] = “21 17/09/2011 43”;
//this.mUIItem211709201143ListItem.WindowTitles.Add(“JanelaExemploListBox”);
#endregion
UITestControlCollection componentes = this.GetChildren();
foreach (UITestControl ui in componentes)
{
if (ui.ControlType.Equals(ControlType.List))
{
UITestControlCollection itensList = ui.GetChildren();
foreach(UITestControl item in itensList)
{
if(item.ControlType.Equals(ControlType.ListItem)
{ return mUIItem211709201143ListItem = (WinListItem)item; }
}
}
}
}
return this.mUIItem211709201143ListItem;
}
}
Não consegui encontrar outra maneira de resolver esse problema e até esse momento está funcionando assim. Aceito sugestões e criticas de como melhorar esse tipo de trabalho.
Conclusão para a definição de um componente é necessário alterar a forma como o mapeamento é feito e atribuir diretamente o componente ao desejado para que as validações da interação seja correta em outras informações passadas.
Código fonte do projeto aqui.
Qualquer dúvida entrar em contato.
Para saber mais:
MSDN Coded UI Test – http://msdn.microsoft.com/en-us/library/dd286726.aspx
Blog MSDN – http://blogs.msdn.com/b/mathew_aniyan/archive/2009/01/20/coded-ui-test.aspx
Comunidade DevBrasil – http://devbrasil.net/group/alm