Angular: Teste de integração (teste superficial)



Quando o aplicativo cresce, ou é muito importante para nós que funcione corretamente com qualquer refatoração, começamos a pensar nos testes de unidade ou e2e.

Por vários anos trabalhando com aplicações Angular no segmento corporativo, tendo encontrado muitos problemas ao refatorar e criar novas funcionalidades, os testes não parecem uma perda de tempo, mas a chave da estabilidade nas mãos dos programadores.

Em seguida, vamos tentar entender como testar o aplicativo básico no Angular e tocar em um pouco de teoria.

Vamos começar com os tipos de teste que os desenvolvedores de aplicativos podem fazer (no nosso caso, frontend).



(Martin Fowler e Blog de testes do Google) A

Angular tem esses métodos prontos para uso.

Vamos dar uma olhada na pirâmide de teste usando o exemplo de aplicativos Angular.

Teste de unidade - teste isolado de métodos de classe. Verificamos a operação do método, passando várias combinações de parâmetros para a entrada e comparamos o resultado com o esperado.

Por exemplo, temos um componente no qual as seqüências hexadecimais são convertidas em rgb, essas informações são exibidas ao usuário e também enviadas ao servidor restante.

Se começarmos a procurar testes de unidade, podemos escrever muitos testes para cada método na classe de componentes.

Se tivermos um método rgbToHex (hex: string) => string, para testar um método com essa assinatura, precisamos fazer o seguinte: expect (rgbToHex ('777')). ToBe ('rgb (119, 119, 119)') .

Parece ótimo, mas temos um problema devido ao grande número de funções que precisam ser cobertas e estamos com preguiça de escrever testes. Além disso, mesmo escrevendo testes de unidade para cada método em um componente, não garantimos a correção de seu trabalho conjunto.

Por exemplo, depois de criar e testar o componente de saída da tabela, podemos chamá-lo no componente “calculadora”, mas especificar acidentalmente a ligação incorreta. Os dados não cairão nas tabelas e os componentes totalmente funcionais não funcionarão corretamente.

imagem

Teste de integração- testando vários componentes. A partir deste estágio, começamos a testar não apenas os métodos de classe, mas também a sua ligação ao html, ou seja, clique nos elementos dentro do componente. O teste superficial é frequentemente encontrado na notação angular , que é essencialmente teste de integração.

Nos testes em Superfície, veremos mais detalhadamente abaixo. Teste

E2E (ponta a ponta) - uma maneira de testar completamente o aplicativo para resolver os problemas dos testes de unidade.

Com essa abordagem, escrevemos scripts de teste para um aplicativo totalmente renderizado, ou seja, todos os componentes e serviços são reunidos e reproduzimos as ações do usuário.
Isso é muito legal, mas podemos ter um problema de alterar stubs dinamicamente (geralmente um servidor json estático no node.js) e, para executar situações diferentes, podemos precisar de dados diferentes do servidor emulado.

Por exemplo: temos uma página com uma lista de usuários, um dos componentes deste painel é a paginação. Ele deve se comportar de maneira diferente com diferentes números de usuários. Mas se os dados no servidor emulado forem definidos via json, o número de usuários será sempre um, e não poderemos verificar todos os casos com um número diferente de páginas.

Como resultado, podemos concluir que, se quisermos alterar stubs com flexibilidade e testar não por métodos, mas por unidades lógicas da interface, precisamos usar algo entre o e2e e os testes de unidade. É aqui que o teste superficial (teste de integração) vem em socorro.

Glossário:

  • Zombarias são objetos para simular respostas em vários casos de uso.
  • Os stubs são os stubs mais estúpidos sem lógica (você pode ler Martin).
  • O karma é um corredor de teste incorporado ao angular (geralmente aconselhado a usar brincadeira, mas não sobre isso hoje).
  • Jasmine é uma estrutura para descrever testes na forma de especificações (veja abaixo).
  • extensão de arquivo spec - test (descrição da especificação no estilo BDD).
  • é o nome dos métodos para testes no Jasmine.
  • xit é o nome dos métodos que não serão executados.
  • fit - se houver métodos com o mesmo nome nas especificações, somente eles serão lançados.

O teste superficial para Angular, bem como para outras estruturas, é uma abordagem de teste de unidade, quando um componente de tamanho grande o suficiente é renderizado para que possa existir como uma unidade de interface do usuário separada com sua própria funcionalidade.

Por exemplo, temos um componente para converter hex -> rgb. Podemos renderizar apenas esse componente, gerar stubs para diferentes situações, executar possíveis casos de uso para esse componente do ponto de vista dos usuários finais e verificar a operação do componente.

Vamos tentar descobrir um exemplo (repositório).

Prepare a classe para acessar os componentes do componente de acordo com o PageObject e adicione um auxiliar à raiz do projeto.

Auxiliar - ajudará a procurar elementos nos componentes que foram selecionados para renderização. Dessa forma, podemos facilitar a vida se usarmos o Material Angular: os elementos do tipo select criarão uma lista com a opção em um bloco separado, e a pesquisa desses elementos pode levar a clichês, e um invólucro na forma de um auxiliar pode ajudar.

export class PageObjectBase {

  constructor(private root: HTMLDivElement) { }
  //    input  
  _inputValue(cssSelector: string, value: string) { 
    if (value) {
      this.root.querySelector<HTMLInputElement>(cssSelector).value = value;
      this.root.querySelector<HTMLInputElement>(cssSelector).dispatchEvent(new Event('input'));
    }
    else {
      return this.root.querySelector<HTMLInputElement>(cssSelector).value
    }
  }
  //          
  _buttonClick(cssSelector: string) {
    this.root.querySelector<HTMLButtonElement>(cssSelector).dispatchEvent(new Event('click'));
  }

}

PageObject é um modelo de teste automatizado popular. Usado para simplificar o suporte para testes escritos. Se alterarmos a interface do usuário, não precisaremos reescrever os testes, basta alterar os seletores de elemento.


export class ConverterFromHexPageObject extends PageObjectBase {

  constructor(root: HTMLDivElement) {
    super(root)
  }

  hex(text?: string) {
    return this._inputValue('.input-hex', text);
  }

  rgb(text?: string) {
    return this._inputValue('.input-rgb', text);
  }

  clear() {
    this._buttonClick('.btn-clear')
  }

  calc() {
    this._buttonClick('.btn-calc')
  }

}

e os próprios testes:


// ,        api   
const urlToSave = 'http://localhost:4200/save-hex';


//  -   
describe('ConverterFromHexComponent', () => {
  let component: ConverterFromHexComponent;
  let fixture: ComponentFixture<ConverterFromHexComponent>;
  let page: ConverterFromHexPageObject;
  let httpTestingController: HttpTestingController;


  //      ,   
  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [ConverterModule, HttpClientTestingModule]
    })
      .compileComponents();
    httpTestingController = TestBed.get(HttpTestingController);
  }));


  //  ,   
  beforeEach(() => {
    fixture = TestBed.createComponent(ConverterFromHexComponent);
    component = fixture.componentInstance;
    page = new ConverterFromHexPageObject(fixture.nativeElement);
    fixture.detectChanges();
  });


  //    ,     http 
  afterEach(() => {
    httpTestingController.verify();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });

  it('should clear', async () => {
    page.hex('112233'); //  input  
    expect(page.hex()).toBe('112233'); // ,    
    await page.clear(); //      
    fixture.detectChanges(); //    
    expect(page.hex()).toBe(''); // ,   clear 
  });

  it('should convert', async () => {
    page.hex('123123');
    expect(page.rgb()).toBe('');
    page.calc();
    const req = httpTestingController.expectOne(urlToSave);
    expect(req.request.method).toEqual('POST');
    expect(req.request.body.hex).toEqual('123123');
    req.flush({});
    await fixture.detectChanges();
    expect(page.rgb()).toBe('rgb(18, 49, 35)');
  });

  it('should convert three-digit hex', async () => {
    page.hex('567');
    expect(page.rgb()).toBe('');
    page.calc();
    const req = httpTestingController.expectOne(urlToSave);
    expect(req.request.method).toEqual('POST');
    req.flush({});
    await fixture.detectChanges();
    expect(page.rgb()).toBe('rgb(85, 102, 119)');
  });

  it('rgb should be empty when entered incorrectly hex', async () => {
    page.hex('qw123we');
    page.calc();
    const req = httpTestingController.expectNone(urlToSave);
    await fixture.detectChanges();
    expect(page.rgb()).toBe('');
  });

});

Tudo parece ser simples, mas aqui estão algumas notas interessantes para o teste Angular Shallow:

  • Sempre verifique se não há solicitações HTTP não reservadas. Isso ajudará você a entender exatamente se existem solicitações desnecessárias para nossa funcionalidade.
  • PageObject , .
  • json , .
  • , .
  • .
  • .
  • , session, local, cookie ( ).
  • fake.js.
  • .




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


All Articles