1659917820
Este artigo serve como um guia para testes unitários de componentes Vue.
Veremos primeiro por que o teste de unidade é importante para a criação de software sustentável e o que você deve testar. Em seguida, detalharemos como:
Dependências :
O código-fonte (junto com instruções detalhadas de instalação) para o projeto Vue Weather App usado neste artigo pode ser encontrado no GitLab: Vue Weather App .
Ao final deste artigo, você deverá ser capaz de:
beforeEach()
e afterEach()
dentro de um conjunto de testes de unidadeEm geral, o teste ajuda a garantir que seu aplicativo funcione conforme o esperado para seus usuários finais.
Projetos de software com alta cobertura de teste nunca são perfeitos, mas é um bom indicador inicial da qualidade do software. Além disso, o código testável geralmente é um sinal de uma boa arquitetura de software, e é por isso que os desenvolvedores avançados levam os testes em consideração durante todo o ciclo de vida do desenvolvimento.
Os testes podem ser considerados em três níveis:
Os testes de unidade testam a funcionalidade de uma unidade individual de código isolada de suas dependências. Eles são a primeira linha de defesa contra erros e inconsistências em sua base de código. O teste de unidade é uma parte fundamental do processo de Desenvolvimento Orientado a Testes (TDD).
O teste de unidade melhora a capacidade de manutenção do seu código.
Manutenibilidade refere-se a fazer correções de bugs ou aprimoramentos em seu código ou a outro desenvolvedor que precise atualizar seu código no futuro.
O teste de unidade deve ser combinado com um processo de Integração Contínua (CI) para garantir que seus testes de unidade sejam executados constantemente, idealmente em cada confirmação para seu repositório. Um conjunto sólido de testes de unidade pode ser fundamental para detectar defeitos rapidamente e no início do processo de desenvolvimento, antes que seus usuários finais os encontrem na produção.
O que você deve testar? Ou, mais importante: O que você não deve testar?
Existem três tipos de testes a serem considerados com testes de unidade:
Como você não pode testar todas as coisas, em que você deve se concentrar?
Concentre-se em testar entradas e saídas com as quais o usuário final irá interagir. A experiência que os usuários do seu produto têm é primordial!
Ao se concentrar em testar as entradas/saídas de um módulo de software (por exemplo, um componente Vue), você está testando os principais aspectos que o usuário final experimentará.
Pode haver outra lógica interna em um módulo de software que seja complexa e precise ser testada na unidade, mas é mais provável que esses tipos de testes precisem de atualização durante uma refatoração de código.
Antes de discutir como testar a unidade dos componentes Vue, quero dar uma breve visão geral do aplicativo Vue Weather que testaremos.
Depois de clonar o repositório, instale as dependências e adicione a chave de API.
Revise o README do projeto para obter mais informações sobre como criar e adicionar a chave de API do Open Weather.
Uma vez feito, o aplicativo Vue Weather pode ser executado em seu computador local iniciando o servidor de desenvolvimento:
$ npm run dev
Depois que o aplicativo for criado, você verá uma mensagem de sucesso semelhante a:
vite v2.9.14 dev server running at:
> Local: http://localhost:3000/
> Network: use `--host` to expose
ready in 543ms.
Neste ponto, o servidor de desenvolvimento estará funcionando. Você pode ver o aplicativo Vue navegando até http://localhost:3000 em seu navegador favorito. Quando você carrega o aplicativo pela primeira vez, nenhum dado é exibido; você verá apenas um campo de entrada para inserir a cidade para a qual deseja obter o clima:
Sem nenhum dado inserido, os botões 'Pesquisar' e 'Limpar' ficam desabilitados.
Assim que você começar a inserir dados para uma cidade (assim que o primeiro caractere for adicionado), os botões 'Pesquisar' e 'Limpar' serão ativados:
Se você clicar em 'Pesquisar' depois de inserir uma cidade válida, os dados meteorológicos serão exibidos para essa cidade:
Neste ponto, clicar no botão 'Clear Weather Data' fará com que os dados meteorológicos sejam apagados:
No entanto, a cidade que foi inserida permanecerá no campo de entrada.
Se você clicar em 'Limpar' agora, o campo de entrada será limpo e os botões 'Pesquisar' e 'Limpar' serão desativados novamente:
O que acontece se você inserir uma cidade inválida? E se você clicar em 'Limpar' antes de 'Limpar dados meteorológicos'? Quais outros estados do aplicativo você pode encontrar?
Como os componentes são os blocos de construção do Vue (e realmente de qualquer estrutura SPA ), eles são a parte mais crucial do seu aplicativo como um todo. Portanto, gaste a maior parte do seu tempo de teste alocado escrevendo testes de unidade que testam os componentes do seu aplicativo.
Com base na minha experiência com componentes Vue de teste de unidade, descobri que as ferramentas e a estrutura de teste - Vite e Vitest - satisfazem os principais aspectos de um bom ambiente de teste:
Felizmente, você descobrirá que o teste de unidade de seus componentes Vue é uma experiência agradável, pois acho que isso é fundamental para incentivar mais testes.
Existem duas ferramentas que vamos usar para testes unitários dos componentes Vue:
Vitest é uma estrutura de teste de unidade que visa ser agnóstica de estrutura, para que possa ser usada para testar Vue, React, Svelte, Lit e outros projetos. O Vitest está configurado para ser executado com o Vite, o que resulta em uma execução de teste rápida .
Se você estiver familiarizado com o Jest, mudar para o Vitest é muito simples, pois a API do Vitest é compatível com o Jest.
Ao escrever testes de unidade para um componente Vue, Vitest e Vue Test Utils fornecem a seguinte funcionalidade:
engrenagem
it
, describe
)expect
, toMatch
, toContain
, etc.)mockResolvedValue
, mockRejectedValue
)beforeEach
, beforeAll
) / Desmontagem ( afterEach
, afterAll
)Ver Utilitários de Teste
mount
, shallowMount
)setProps
)findAll('h2')
)flushPromises()
)trigger
)emitted
)O Vitest fornece a funcionalidade genérica para escrever testes de unidade enquanto o Vue Test Utils fornece os utilitários de teste específicos do Vue.
Para começar, vamos discutir a convenção de nomenclatura para testes de unidade no Vue. O arquivo de teste de unidade deve ter o seguinte formato:
<ComponentName>
.spec.jsDe acordo com o Guia de Estilo Vue , os nomes dos componentes devem ter várias palavras (
WeatherHeader
em vez de apenasHeader
) para evitar conflitos com elementos HTML.
Você normalmente deve ter um arquivo de teste de unidade para cada componente em seu projeto Vue. Dentro de cada arquivo de teste de unidade, pode haver um único conjunto de testes de unidade ou vários conjuntos de testes de unidade.
Os arquivos de teste de unidade devem ser colocados em uma subpasta dentro da pasta Componentes ( src/components/__tests__ ):
$ tree -d -L 2
.
├── node_modules
├── public
├── src
├── assets
└── components
└── __tests__
O Vitest pode ser usado para executar os testes de unidade assim:
$ npm run test:unit
✓ src/components/__tests__/WeatherFooter.spec.js (1)
✓ src/components/__tests__/WeatherHeader.spec.js (1)
✓ src/components/__tests__/WeatherResult.spec.js (3)
✓ src/components/__tests__/WeatherBanner.spec.js (5)
✓ src/components/__tests__/WeatherSearch.spec.js (5)
✓ src/components/__tests__/App.spec.js (7)
Test Files 6 passed (6)
Tests 22 passed (22)
Time 2.38s (in thread 640ms, 371.13%)
Todos os comandos disponíveis para execução
npm
em seu projeto Vue são definidos noscripts
campo em package.json .
A configuração padrão do Vitest é executar os testes no modo de observação , o que significa que o conjunto de testes será executado novamente a cada salvamento em um arquivo aplicável. Para alterar essa configuração para que o Vitest seja executado apenas uma vez (sem "modo de observação"), atualize a test:unit
configuração em package.json para incluir o run
argumento:
"test:unit": "vitest run --environment jsdom",
Usando o aplicativo Vue Weather , vamos ver alguns exemplos para testar componentes Vue.
Vamos pular direto para um exemplo de um arquivo de teste de unidade no Vue! O primeiro arquivo de teste de unidade é encontrado em src/components/__tests__/WeatherHeader.spec.js e testa o WeatherHeader
componente:
import { describe, it, expect } from 'vitest'
import { shallowMount } from '@vue/test-utils'
import WeatherHeader from '../WeatherHeader.vue'
describe('WeatherHeader.vue Test', () => {
it('renders message when component is created', () => {
// render the component
const wrapper = shallowMount(WeatherHeader, {
propsData: {
title: 'Vue Project'
}
})
// check that the title is rendered
expect(wrapper.text()).toMatch('Vue Project')
})
})
A primeira linha neste arquivo importa as funções de teste do Vitest que são usadas neste arquivo.
Se você quiser que a API Vitest esteja disponível globalmente (como o Jest funciona), adicione
test: {globals: true}
adefineConfig()
função em vite.config.js . Para mais detalhes, confira a documentação do Vitest .
A segunda linha neste arquivo importa uma função chamada shallowMount
da biblioteca Vue Test Utils. A ideia de 'montagem' significa o carregamento de um componente individual para poder testá-lo. Existem dois métodos para isso no Vue Test Utils:
shallowMount()
- cria um wrapper
para o componente Vue, mas com componentes filhos stubbedmount()
- cria um wrapper
para o componente Vue, incluindo a montagem de qualquer componente filhoComo nosso foco é testar um componente individual (o WeatherHeader
componente), usaremos shallowMount()
.
shallowMount()
é melhor para testar um componente individual isoladamente, pois os componentes filhos são stubs. Esta é a situação ideal para testes unitários .Além disso, usar
shallowMount()
para testar um componente com muitos componentes filho pode melhorar o tempo de execução do teste de unidade, pois não há custo (em termos de tempo) para renderizar os componentes filhos.
mount()
é útil quando você deseja incluir o teste do comportamento dos componentes filho.
A terceira linha importa o componente Vue que será testado, WeatherHeader.vue .
Após as import
instruções, há um describe
bloco que define um conjunto de testes de unidade.
Dentro de um arquivo de teste de unidade, pode haver vários describe
blocos que definem diferentes conjuntos de testes de unidade. Da mesma forma, cada describe
bloco pode conter vários testes de unidade, onde cada teste de unidade é definido por um it
bloco.
Considero essa distinção como:
describe
bloco - suíte de teste de unidadeit
bloco - função de teste de unidade individualO que é bom sobre o teste de unidade com o Vitest é que existem vários incentivos embutidos para adicionar comentários. Por exemplo, o primeiro argumento para describe
deve explicar claramente qual componente Vue está sendo testado:
describe('WeatherHeader.vue Test', () => { ... })
Para cada it
bloco, o primeiro argumento é uma descrição da função de teste, que deve ser uma breve descrição do que esse teste específico está fazendo. No exemplo acima, o it
bloco testa se o componente 'renderiza a mensagem quando o componente é criado'.
Quanto ao teste unitário real, o primeiro passo é montar o componente Vue para que possa ser testado:
// render the component
const wrapper = shallowMount(WeatherHeader, {
propsData: {
title: 'Vue Project'
}
})
A shallowMount
função retorna um wrapper
objeto, que contém o componente montado e os métodos para testar esse componente. O wrapper
objeto nos permite testar todos os aspectos do HTML gerado pelo componente Vue e todas as propriedades (como dados) do componente Vue.
Além disso, as props, passadas para o WeatherHeader
componente, são passadas como o segundo argumento para shallowMount()
.
A verificação real realizada no teste de unidade é:
// check that the title is rendered
expect(wrapper.text()).toMatch('Vue Project')
Esta linha serve wrapper
para verificar se o título gerado pelo componente é 'Vue Project'. Como essa verificação faz uma comparação de strings, é recomendável usar toMatch()
.
Enquanto as verificações no arquivo de teste de unidade para o WeatherHeader
componente estão apenas verificando valores de string, existem [muitas opções disponíveis no Vitest para realizar verificações:
toBeTruthy()
- verifica se uma variável/instrução é verdadeiratoBeFalsy()
- verifica se uma variável/instrução é falsatoBeNull()
- verifica se uma variável corresponde apenas a nulltoBeUndefined()
- verifica se uma variável não está definidatoBeDefined()
- verifica se uma variável está definidatoBeGreaterThan()
- verifica se um número é maior que o valor especificadotoBeGreaterThanOrEqual()
- verifica se um número é maior ou igual ao valor especificadotoBeLessThan()
- verifica se um número é menor que o valor especificadotoBeLessThanOrEqual()
- verifica se um número é menor ou igual ao valor especificadotoBe()
e toEqual()
- verifica se um número é igual ao valor especificado (essas funções são equivalentes para números)toBeCloseTo()
- verifica se um número é igual ao valor especificado dentro de uma pequena tolerância (útil para números de ponto flutuante)toMatch()
- verifica se uma string é igual ao valor especificado (Regex pode ser usado como o valor especificado!)toContain()
- verifica se um array contém o valor especificadoAlém disso, o not
qualificador pode ser usado com a maioria destas verificações:
expect(wrapper.text()).not.toMatch('Node Project')
Para obter uma lista completa de verificações disponíveis, confira a referência da API Vitest .
Este exemplo mostra como testar as condições iniciais (ou estado) do WeatherResult
componente.
Aqui está um esboço do arquivo de teste de unidade (definido em src/components/__tests__/WeatherResult.spec.js ):
import { describe, it, expect, beforeEach, afterEach } from 'vitest'
import { shallowMount, flushPromises } from '@vue/test-utils'
import WeatherResult from '@/components/WeatherResult.vue'
describe('WeatherResult.vue Implementation Test', () => {
let wrapper = null
// SETUP - run before to each unit test
beforeEach(() => {
// render the component
wrapper = shallowMount(WeatherResult, {
propsData: {
city: '',
weatherSummary: '',
weatherDescription: '',
currentTemperature: 0.0,
lowTemperature: 0.0,
highTemperature: 0.0
}
})
})
// TEARDOWN - run after to each unit test
afterEach(() => {
wrapper.unmount()
})
it('initializes with correct elements', () => { ... })
it('processes valid props data', async () => { ... })
it('emits a custom event when the Clear Weather Data button is clicked', () => { ... })
})
O arquivo de teste de unidade utiliza a shallowMount()
função para renderizar o WeatherResult
componente, pois esse componente é testado como um componente individual isoladamente.
Dentro do conjunto de testes de unidade (definido dentro do describe
bloco), existem duas novas funções definidas:
beforeEach()
- chamado antes da execução de cada teste de unidade dentro deste conjunto de testes de unidadeafterEach()
- chamado após a execução de cada teste de unidade dentro deste conjunto de testes de unidadeA beforeEach()
função é usada para definir um estado consistente antes de executar cada teste de unidade. Esse conceito é muito importante para garantir que a ordem de execução dos testes unitários não afete os resultados dos testes unitários como um todo.
Neste exemplo, a beforeEach()
função renderiza o componente com um conjunto padrão de dados de prop:
// SETUP - run before to each unit test
beforeEach(() => {
// render the component
wrapper = shallowMount(WeatherResult, {
propsData: {
city: '',
weatherSummary: '',
weatherDescription: '',
currentTemperature: 0.0,
lowTemperature: 0.0,
highTemperature: 0.0
}
})
})
A afterEach()
função é usada para limpar qualquer processamento realizado durante o teste de unidade.
Neste exemplo, a afterEach()
função desmonta o wrapper
usado durante o teste de unidade, para que wrapper
possa ser reinicializado para o próximo teste de unidade no beforeEach()
:
// TEARDOWN - run after to each unit test
afterEach(() => {
wrapper.unmount()
})
Se você deseja executar o código que é executado antes ou depois da execução do conjunto geral de testes de unidade, você pode usar:
beforeAll(() => {
/* Runs before all tests */
})
afterAll(() => {
/* Runs after all tests */
})
O primeiro teste de unidade verifica as condições iniciais do WeatherResult
componente:
it('initializes with correct elements', () => {
// check that the heading text is rendered
expect(wrapper.findAll('h2').length).toEqual(2)
expect(wrapper.findAll('h2').at(0).text()).toMatch('Weather Summary')
expect(wrapper.findAll('h2').at(1).text()).toMatch('Temperatures')
// check that 6 fields of data for the temperature are displayed
expect(wrapper.findAll('p').length).toEqual(6)
expect(wrapper.findAll('p').at(0).text()).toMatch('City:')
expect(wrapper.findAll('p').at(1).text()).toMatch('Summary:')
expect(wrapper.findAll('p').at(2).text()).toMatch('Details:')
expect(wrapper.findAll('p').at(3).text()).toMatch('Current: 0° F')
expect(wrapper.findAll('p').at(4).text()).toMatch('High (Today): 0° F')
expect(wrapper.findAll('p').at(5).text()).toMatch('Low (Today): 0° F')
})
Verificações:
expect
s verifica se os dois cabeçalhos (definidos como h2
elementos) estão conforme o esperado.expect
s verifica se os seis campos de dados (definidos como p
elementos) estão conforme o esperado.O segundo teste de unidade verifica se os dados válidos passados como dados prop são tratados corretamente pelo WeatherResult
componente:
it('processes valid props data', async () => {
// Update the props passed in to the WeatherResult component
wrapper.setProps({
city: 'Chicago',
weatherSummary: 'Cloudy',
weatherDescription: 'Cloudy with a chance of rain',
currentTemperature: 45.1,
lowTemperature: 42.0,
highTemperature: 47.7
})
// Wait until the DOM updates
await flushPromises()
// check that the prop data is stored as expected within the component
expect(wrapper.vm.city).toMatch('Chicago')
expect(wrapper.vm.weatherSummary).toMatch('Cloudy')
expect(wrapper.vm.weatherDescription).toMatch('Cloudy with a chance of rain')
expect(wrapper.vm.currentTemperature).toEqual(45.1)
expect(wrapper.vm.lowTemperature).toBeCloseTo(42.0)
expect(wrapper.vm.highTemperature).toBe(47.7)
// check that the heading text is rendered
expect(wrapper.findAll('h2').length).toEqual(2)
expect(wrapper.findAll('h2').at(0).text()).toMatch('Weather Summary')
expect(wrapper.findAll('h2').at(1).text()).toMatch('Temperatures')
// check that 6 fields of data for the temperature are displayed
expect(wrapper.findAll('p').length).toEqual(6)
expect(wrapper.findAll('p').at(0).text()).toMatch('City: Chicago')
expect(wrapper.findAll('p').at(1).text()).toMatch('Summary: Cloudy')
expect(wrapper.findAll('p').at(2).text()).toMatch('Details: Cloudy with a chance of rain')
expect(wrapper.findAll('p').at(3).text()).toMatch('Current: 45.1° F')
expect(wrapper.findAll('p').at(4).text()).toMatch('High (Today): 47.7° F')
expect(wrapper.findAll('p').at(5).text()).toMatch('Low (Today): 42° F')
})
Como a beforeEach()
função fornece um conjunto padrão de dados de prop, precisamos substituir os dados de prop usando a setProps()
função.
Para garantir que os dados do prop causem as atualizações esperadas no WeatherResult
, o teste precisa aguardar que todas as atualizações do DOM entrem em vigor:
// Wait until the DOM updates
await flushPromises()
NOTA: O uso de
await
só é possível se a função for definida comasync
!
Verificações:
WeatherResult
componente verificando os elementos de dados (usando wrapper.vm
).expect
s verifica se os dois cabeçalhos (definidos como h2
elementos) estão conforme o esperado.expect
s verifica se os dados da prop são usados para definir os seis campos de dados (definidos como p
elementos) conforme o esperado.O terceiro teste de unidade verifica se o clear-weather-data
evento é emitido pelo WeatherResult
componente quando o usuário clica no botão 'Clear Weather Data':
it('emits a custom event when the Clear Weather Data button is clicked', () => {
// trigger an event when the 'Clear Weather Data' button is clicked
wrapper.findAll('button').at(0).trigger('click')
// check that 1 occurrence of the event has been emitted
expect(wrapper.emitted('clear-weather-data')).toBeTruthy()
expect(wrapper.emitted('clear-weather-data').length).toBe(1)
})
Para acionar um evento de clique, o button
elemento deve ser encontrado no wrapper
e então a trigger
função é chamada para acionar o evento de clique.
Uma vez que o botão é clicado, o teste de unidade verifica se apenas um evento personalizado (com o nome de clear-weather-data
) é emitido.
Dentro do App
componente, quando um usuário pesquisa o clima de uma cidade, uma chamada HTTP GET é feita para o Open Weather para recuperar os dados por meio de uma biblioteca de terceiros chamada Axios :
const searchCity = (inputCity) => {
// GET request for user data
axios.get('http://api.openweathermap.org/data/2.5/weather?q=' + inputCity + '&units=imperial&APPID=' + openweathermapApiKey.value)
.then((response) => {
// handle success
console.log(response)
weatherData.value.city = response.data.name
weatherData.value.weatherSummary = response.data.weather[0].main
weatherData.value.weatherDescription = response.data.weather[0].description
weatherData.value.currentTemperature = response.data.main.temp
weatherData.value.lowTemperature = response.data.main.temp_min
weatherData.value.highTemperature = response.data.main.temp_max
validWeatherData.value = true
})
.catch((error) => {
// handle error
messageType.value = 'Error'
messageToDisplay.value = 'ERROR! Unable to retrieve weather data for ' + inputCity + '!'
console.log(error.message)
resetData()
})
.finally((response) => {
// always executed
console.log('HTTP GET Finished!')
})
}
Ao pensar em como testar as chamadas HTTP GET, dois cenários vêm à mente, cada um testando o efeito colateral da chamada real da API:
Ao testar o código que utiliza uma API externa, geralmente é mais fácil não fazer a chamada real, substituindo a chamada por uma simulação. Existem prós e contras nessa abordagem, no entanto.
Prós:
Contras:
Em algum momento, você deve verificar a integração completa para garantir que a forma da resposta da API não foi alterada.
Como este artigo é focado em testes de unidade, vamos zombar da biblioteca Axios.
A simulação fornece um meio de imitar o comportamento esperado de um módulo de software. Embora o mocking possa ser usado no código de produção (muito perigoso!), normalmente é usado durante o desenvolvimento e teste.
O carregamento de dados de uma API externa leva tempo. Embora normalmente leve menos de um ou dois segundos para carregar os dados do Open Weather neste aplicativo, outras APIs externas podem consumir mais tempo. Além disso, queremos uma maneira de verificar facilmente se a solicitação HTTP GET falha. Portanto, adicionaremos simulações para especificar como a solicitação GET responderia.
Os testes de unidade para o App
componente estão localizados no arquivo src/components/__tests__/App.spec.js .
Para começar, precisamos import
da biblioteca Axios:
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
import { shallowMount, mount, flushPromises } from '@vue/test-utils'
import App from '../../App.vue'
import axios from 'axios'
No entanto, não queremos usar a biblioteca Axios real como é feito no código-fonte ( App.vue ). Em vez disso, queremos criar uma simulação da biblioteca Axios para que não chamemos a API externa:
// Mock the axios library
vi.mock("axios", () => {
return {
default: {
get: vi.fn(),
},
};
});
Este bloco de código diz ao Vitest que o get()
método dentro da axios
biblioteca deve ser simulado.
No arquivo de teste de unidade ( src/components/__tests__/App.spec.js ), para o App
componente, temos:
Para começar, vamos lidar com a situação nominal em que a solicitação HTTP GET é bem-sucedida.
describe('Implementation Test for App.vue with Successful HTTP GET', () => {
let wrapper = null
beforeEach(() => {
const responseGet = { data:
{
name: 'Chicago',
weather: [
{
main: 'Cloudy',
description: 'Cloudy with a chance of rain'
}
],
main: {
temp: 56.3,
temp_min: 53.8,
temp_max: 58.6
}
}
}
// Set the mock call to GET to return a successful GET response
axios.get.mockResolvedValue(responseGet)
// render the component
wrapper = shallowMount(App)
})
afterEach(() => {
axios.get.mockReset()
wrapper.unmount()
})
...
})
Na beforeEach()
função, definimos a resposta que deve ocorrer quando axios.get()
for chamado. A resposta são os dados meteorológicos pré-enlatados que se parecem com o que obtemos do Open Weather, se realmente fizermos a solicitação. A linha chave nesta seção é:
// Set the mock call to GET to return a successful GET response
axios.get.mockResolvedValue(responseGet)
Esta linha é a chave, pois permite ao Vitest saber que deve retornar o responseGet
array quando axios.get()
for chamado no App
componente, em vez de realmente fazer uma chamada HTTP GET usando o Axios.
A próxima seção do conjunto de testes de unidade define a afterEach()
função:
afterEach(() => {
axios.get.mockReset()
wrapper.unmount()
})
A afterEach()
função, que é chamada após a execução de cada teste de unidade, limpa a simulação axios.get()
que foi criada durante a execução do teste de unidade. Essa abordagem é uma boa prática para limpar quaisquer simulações após a execução de um teste, para que todos os testes subsequentes comecem a partir de um estado conhecido.
Agora podemos definir o teste de unidade:
it('does load the weather data when a successful HTTP GET occurs', async () => {
wrapper.vm.searchCity('Chicago')
// Wait until the DOM updates
await flushPromises()
expect(axios.get).toHaveBeenCalledTimes(1)
expect(axios.get).toBeCalledWith(expect.stringMatching(/Chicago/))
// check that the user data is properly set
expect(wrapper.vm.weatherData.city).toMatch('Chicago')
expect(wrapper.vm.weatherData.weatherSummary).toMatch('Cloudy')
expect(wrapper.vm.weatherData.weatherDescription).toMatch('Cloudy with a chance of rain')
expect(wrapper.vm.weatherData.currentTemperature).toEqual(56.3)
expect(wrapper.vm.weatherData.lowTemperature).toEqual(53.8)
expect(wrapper.vm.weatherData.highTemperature).toEqual(58.6)
expect(wrapper.vm.validWeatherData).toBe(true)
})
Como já passamos pelas etapas de definição do mock e renderização do componente (via shallowMount()
), este teste de unidade pode se concentrar em realizar verificações.
O teste de unidade começa chamando a searchCity()
função:
wrapper.vm.searchCity('Chicago')
Para garantir que a searchCity()
função cause as atualizações esperadas no App
componente, o teste precisa aguardar que todas as Promises sejam resolvidas e que as atualizações do DOM entrem em vigor:
// Wait until all Promises are resolved and the DOM updates
await flushPromises()
Verificamos que axios.get()
foi chamado apenas uma vez e que a chamada HTTP GET incluiu o nome correto da cidade:
expect(axios.get).toHaveBeenCalledTimes(1)
expect(axios.get).toBeCalledWith(expect.stringMatching(/Chicago/))
Para ser muito completo, os dados meteorológicos também verificam a instância do App
componente renderizado neste teste de unidade para garantir que ele corresponda aos dados pré-enlatados retornados da simulação de axios.get()
:
// check that the user data is properly set
expect(wrapper.vm.weatherData.city).toMatch('Chicago')
expect(wrapper.vm.weatherData.weatherSummary).toMatch('Cloudy')
expect(wrapper.vm.weatherData.weatherDescription).toMatch('Cloudy with a chance of rain')
expect(wrapper.vm.weatherData.currentTemperature).toEqual(56.3)
expect(wrapper.vm.weatherData.lowTemperature).toEqual(53.8)
expect(wrapper.vm.weatherData.highTemperature).toEqual(58.6)
expect(wrapper.vm.validWeatherData).toBe(true)
Embora seja bom testar quando as coisas acontecem conforme o esperado, também é importante verificar como nosso software reage a condições negativas. Com isso em mente, vamos criar um segundo conjunto de testes de unidade para verificar uma solicitação HTTP GET com falha:
describe('Implementation Test for App.vue with Failed HTTP GET', () => { ... })
Não há problema em ter vários conjuntos de testes de unidade em um único arquivo de teste de unidade ( .spec.js ).
Como os mocks são criados na
beforeEach()
função, é necessário haver conjuntos de testes de unidade separados combeforeEach()
implementações diferentes para respostas HTTP GET bem-sucedidas e com falha.
A beforeEach()
função neste conjunto de testes de unidade é bem diferente:
beforeEach(() => {
// Set the mock call to GET to return a failed GET request
axios.get.mockRejectedValue(new Error('BAD REQUEST'))
// Render the component
wrapper = shallowMount(App)
})
Em vez de definir uma resposta para retornar da axios.get()
chamada, agora estamos retornando um Promise
objeto com falha com a resposta de 'BAD REQUEST'.
A afterEach()
função para este conjunto de testes de unidade é idêntica ao outro conjunto de testes de unidade:
afterEach(() => {
axios.get.mockReset()
wrapper.unmount()
})
Aqui está a função de teste de unidade para testar uma solicitação HTTP GET com falha:
it('does not load the weather data when a failed HTTP GET occurs', async () => {
wrapper.vm.searchCity('Chicago')
expect(axios.get).toHaveBeenCalledTimes(1)
expect(axios.get).toBeCalledWith(expect.stringMatching(/Chicago/))
// Wait until the DOM updates
await flushPromises()
// Check that there is no user data loaded when the GET request fails
expect(wrapper.vm.weatherData.city).toMatch(/^$/)
expect(wrapper.vm.weatherData.weatherSummary).toMatch(/^$/)
expect(wrapper.vm.weatherData.weatherDescription).toMatch(/^$/)
expect(wrapper.vm.weatherData.currentTemperature).toEqual(0)
expect(wrapper.vm.weatherData.lowTemperature).toEqual(0)
expect(wrapper.vm.weatherData.highTemperature).toEqual(0)
expect(wrapper.vm.validWeatherData).toBe(false)
// check that the banner message indicates failure
expect(wrapper.vm.messageToDisplay).toMatch('ERROR! Unable to retrieve weather data for Chicago!')
expect(wrapper.vm.messageType).toMatch('Error')
})
Assim como no conjunto de testes de unidade anterior, verificamos se apenas uma instância de axios.get()
é chamada e, em seguida, verificamos se nenhum dado climático foi carregado no App
componente.
Ao desenvolver testes de unidade, pode ser bom entender quanto do código-fonte é realmente testado. Esse conceito é conhecido como cobertura de código.
Preciso deixar bem claro que ter um conjunto de testes de unidade que cobrem 100% do código-fonte não é de forma alguma um indicador de que o código foi testado adequadamente.
Essa métrica significa que há muitos testes de unidade e muito esforço foi feito para desenvolver os testes de unidade. A qualidade dos testes unitários ainda precisa ser verificada por inspeção de código.
O outro extremo onde este é um conjunto mínimo (ou nenhum!) de testes de unidade é um indicador muito ruim.
Vitest fornece cobertura de código usando o --coverage
sinalizador.
Para executar facilmente o Vitest com resultados de cobertura, gosto de incluir os seguintes itens na script
seção de package.json :
{
"name": "vue-weather-app",
"version": "1.0.0",
"scripts": {
...
"test:unit": "vitest run --environment jsdom",
"test:coverage": "vitest run --environment jsdom --coverage",
"test:ui": "vitest --environment jsdom --coverage --ui"
},
...
}
Quando npm run test:unit
é executado, os testes de unidade são executados:
$ npm run test:unit
...
✓ src/components/__tests__/WeatherBanner.spec.js (5)
✓ src/components/__tests__/WeatherSearch.spec.js (5)
✓ src/components/__tests__/WeatherFooter.spec.js (1)
✓ src/components/__tests__/WeatherHeader.spec.js (1)
✓ src/components/__tests__/WeatherResult.spec.js (3)
✓ src/components/__tests__/App.spec.js (7)
Test Files 6 passed (6)
Tests 22 passed (22)
Time 2.81s (in thread 536ms, 524.89%)
Quando npm run test:coverage
executado, os testes de unidade são executados e a cobertura é relatada:
$ npm run test:coverage
...
Test Files 6 passed (6)
Tests 22 passed (22)
Time 3.38s (in thread 660ms, 512.10%)
--------------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
--------------------|---------|----------|---------|---------|-------------------
All files | 99.15 | 96.55 | 100 | 99.15 |
src | 97.31 | 85.71 | 100 | 97.31 |
App.vue | 97.31 | 85.71 | 100 | 97.31 | 60-63
src/components | 100 | 100 | 100 | 100 |
WeatherBanner.vue | 100 | 100 | 100 | 100 |
WeatherFooter.vue | 100 | 100 | 100 | 100 |
WeatherHeader.vue | 100 | 100 | 100 | 100 |
WeatherResult.vue | 100 | 100 | 100 | 100 |
WeatherSearch.vue | 100 | 100 | 100 | 100 |
--------------------|---------|----------|---------|---------|-------------------
O npm run test:ui
carregará os resultados do teste e da cobertura em seu navegador da Web padrão, o que pode ser conveniente para ver visualmente onde está faltando a cobertura do teste.
Depois de passar por vários arquivos de teste de unidade diferentes, recomendo a seguinte estrutura para o arquivo de teste de unidade para um componente Vue:
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
import { shallowMount } from '@vue/test-utils'
import App from '@/App.vue' // Import Vue component to test
import axios from 'axios' // Import libraries to mock
// Mock the axios library
vi.mock("axios", () => {
return {
default: {
get: vi.fn(),
},
};
});
describe('Tests for the ... Component', () => {
let wrapper = null
beforeEach(() => {
// set any initial data and create the mocks of libraries
// render the component
wrapper = shallowMount(App)
})
afterEach(() => {
axios.get.mockReset()
wrapper.unmount()
})
it('check successful events', () => { ... })
it('check failure events', () => { ... })
})
Itens chave:
beforeEach()
e afterEach()
para criar funções de teste de unidade independentesbeforeEach()
função e atualize os dados da prop nas funções de teste de unidadeshallowMount()
over mount()
para se concentrar em testar componentes individuaisEste artigo fornece um guia para testes de unidade de componentes Vue, com foco em:
Simplificando, ao considerar o que testar, concentre-se em testar as entradas e saídas (resultados reais), não a lógica de negócios subjacente (como os resultados são produzidos). Com isso em mente, reserve um ou dois minutos para revisar os exemplos novamente, anotando as entradas e saídas testadas.
Fonte: https://testdrive.io
1600583123
In this article, we are going to list out the most popular websites using Vue JS as their frontend framework.
Vue JS is one of those elite progressive JavaScript frameworks that has huge demand in the web development industry. Many popular websites are developed using Vue in their frontend development because of its imperative features.
This framework was created by Evan You and still it is maintained by his private team members. Vue is of course an open-source framework which is based on MVVM concept (Model-view view-Model) and used extensively in building sublime user-interfaces and also considered a prime choice for developing single-page heavy applications.
Released in February 2014, Vue JS has gained 64,828 stars on Github, making it very popular in recent times.
Evan used Angular JS on many operations while working for Google and integrated many features in Vue to cover the flaws of Angular.
“I figured, what if I could just extract the part that I really liked about Angular and build something really lightweight." - Evan You
#vuejs #vue #vue-with-laravel #vue-top-story #vue-3 #build-vue-frontend #vue-in-laravel #vue.js
1659917820
Este artigo serve como um guia para testes unitários de componentes Vue.
Veremos primeiro por que o teste de unidade é importante para a criação de software sustentável e o que você deve testar. Em seguida, detalharemos como:
Dependências :
O código-fonte (junto com instruções detalhadas de instalação) para o projeto Vue Weather App usado neste artigo pode ser encontrado no GitLab: Vue Weather App .
Ao final deste artigo, você deverá ser capaz de:
beforeEach()
e afterEach()
dentro de um conjunto de testes de unidadeEm geral, o teste ajuda a garantir que seu aplicativo funcione conforme o esperado para seus usuários finais.
Projetos de software com alta cobertura de teste nunca são perfeitos, mas é um bom indicador inicial da qualidade do software. Além disso, o código testável geralmente é um sinal de uma boa arquitetura de software, e é por isso que os desenvolvedores avançados levam os testes em consideração durante todo o ciclo de vida do desenvolvimento.
Os testes podem ser considerados em três níveis:
Os testes de unidade testam a funcionalidade de uma unidade individual de código isolada de suas dependências. Eles são a primeira linha de defesa contra erros e inconsistências em sua base de código. O teste de unidade é uma parte fundamental do processo de Desenvolvimento Orientado a Testes (TDD).
O teste de unidade melhora a capacidade de manutenção do seu código.
Manutenibilidade refere-se a fazer correções de bugs ou aprimoramentos em seu código ou a outro desenvolvedor que precise atualizar seu código no futuro.
O teste de unidade deve ser combinado com um processo de Integração Contínua (CI) para garantir que seus testes de unidade sejam executados constantemente, idealmente em cada confirmação para seu repositório. Um conjunto sólido de testes de unidade pode ser fundamental para detectar defeitos rapidamente e no início do processo de desenvolvimento, antes que seus usuários finais os encontrem na produção.
O que você deve testar? Ou, mais importante: O que você não deve testar?
Existem três tipos de testes a serem considerados com testes de unidade:
Como você não pode testar todas as coisas, em que você deve se concentrar?
Concentre-se em testar entradas e saídas com as quais o usuário final irá interagir. A experiência que os usuários do seu produto têm é primordial!
Ao se concentrar em testar as entradas/saídas de um módulo de software (por exemplo, um componente Vue), você está testando os principais aspectos que o usuário final experimentará.
Pode haver outra lógica interna em um módulo de software que seja complexa e precise ser testada na unidade, mas é mais provável que esses tipos de testes precisem de atualização durante uma refatoração de código.
Antes de discutir como testar a unidade dos componentes Vue, quero dar uma breve visão geral do aplicativo Vue Weather que testaremos.
Depois de clonar o repositório, instale as dependências e adicione a chave de API.
Revise o README do projeto para obter mais informações sobre como criar e adicionar a chave de API do Open Weather.
Uma vez feito, o aplicativo Vue Weather pode ser executado em seu computador local iniciando o servidor de desenvolvimento:
$ npm run dev
Depois que o aplicativo for criado, você verá uma mensagem de sucesso semelhante a:
vite v2.9.14 dev server running at:
> Local: http://localhost:3000/
> Network: use `--host` to expose
ready in 543ms.
Neste ponto, o servidor de desenvolvimento estará funcionando. Você pode ver o aplicativo Vue navegando até http://localhost:3000 em seu navegador favorito. Quando você carrega o aplicativo pela primeira vez, nenhum dado é exibido; você verá apenas um campo de entrada para inserir a cidade para a qual deseja obter o clima:
Sem nenhum dado inserido, os botões 'Pesquisar' e 'Limpar' ficam desabilitados.
Assim que você começar a inserir dados para uma cidade (assim que o primeiro caractere for adicionado), os botões 'Pesquisar' e 'Limpar' serão ativados:
Se você clicar em 'Pesquisar' depois de inserir uma cidade válida, os dados meteorológicos serão exibidos para essa cidade:
Neste ponto, clicar no botão 'Clear Weather Data' fará com que os dados meteorológicos sejam apagados:
No entanto, a cidade que foi inserida permanecerá no campo de entrada.
Se você clicar em 'Limpar' agora, o campo de entrada será limpo e os botões 'Pesquisar' e 'Limpar' serão desativados novamente:
O que acontece se você inserir uma cidade inválida? E se você clicar em 'Limpar' antes de 'Limpar dados meteorológicos'? Quais outros estados do aplicativo você pode encontrar?
Como os componentes são os blocos de construção do Vue (e realmente de qualquer estrutura SPA ), eles são a parte mais crucial do seu aplicativo como um todo. Portanto, gaste a maior parte do seu tempo de teste alocado escrevendo testes de unidade que testam os componentes do seu aplicativo.
Com base na minha experiência com componentes Vue de teste de unidade, descobri que as ferramentas e a estrutura de teste - Vite e Vitest - satisfazem os principais aspectos de um bom ambiente de teste:
Felizmente, você descobrirá que o teste de unidade de seus componentes Vue é uma experiência agradável, pois acho que isso é fundamental para incentivar mais testes.
Existem duas ferramentas que vamos usar para testes unitários dos componentes Vue:
Vitest é uma estrutura de teste de unidade que visa ser agnóstica de estrutura, para que possa ser usada para testar Vue, React, Svelte, Lit e outros projetos. O Vitest está configurado para ser executado com o Vite, o que resulta em uma execução de teste rápida .
Se você estiver familiarizado com o Jest, mudar para o Vitest é muito simples, pois a API do Vitest é compatível com o Jest.
Ao escrever testes de unidade para um componente Vue, Vitest e Vue Test Utils fornecem a seguinte funcionalidade:
engrenagem
it
, describe
)expect
, toMatch
, toContain
, etc.)mockResolvedValue
, mockRejectedValue
)beforeEach
, beforeAll
) / Desmontagem ( afterEach
, afterAll
)Ver Utilitários de Teste
mount
, shallowMount
)setProps
)findAll('h2')
)flushPromises()
)trigger
)emitted
)O Vitest fornece a funcionalidade genérica para escrever testes de unidade enquanto o Vue Test Utils fornece os utilitários de teste específicos do Vue.
Para começar, vamos discutir a convenção de nomenclatura para testes de unidade no Vue. O arquivo de teste de unidade deve ter o seguinte formato:
<ComponentName>
.spec.jsDe acordo com o Guia de Estilo Vue , os nomes dos componentes devem ter várias palavras (
WeatherHeader
em vez de apenasHeader
) para evitar conflitos com elementos HTML.
Você normalmente deve ter um arquivo de teste de unidade para cada componente em seu projeto Vue. Dentro de cada arquivo de teste de unidade, pode haver um único conjunto de testes de unidade ou vários conjuntos de testes de unidade.
Os arquivos de teste de unidade devem ser colocados em uma subpasta dentro da pasta Componentes ( src/components/__tests__ ):
$ tree -d -L 2
.
├── node_modules
├── public
├── src
├── assets
└── components
└── __tests__
O Vitest pode ser usado para executar os testes de unidade assim:
$ npm run test:unit
✓ src/components/__tests__/WeatherFooter.spec.js (1)
✓ src/components/__tests__/WeatherHeader.spec.js (1)
✓ src/components/__tests__/WeatherResult.spec.js (3)
✓ src/components/__tests__/WeatherBanner.spec.js (5)
✓ src/components/__tests__/WeatherSearch.spec.js (5)
✓ src/components/__tests__/App.spec.js (7)
Test Files 6 passed (6)
Tests 22 passed (22)
Time 2.38s (in thread 640ms, 371.13%)
Todos os comandos disponíveis para execução
npm
em seu projeto Vue são definidos noscripts
campo em package.json .
A configuração padrão do Vitest é executar os testes no modo de observação , o que significa que o conjunto de testes será executado novamente a cada salvamento em um arquivo aplicável. Para alterar essa configuração para que o Vitest seja executado apenas uma vez (sem "modo de observação"), atualize a test:unit
configuração em package.json para incluir o run
argumento:
"test:unit": "vitest run --environment jsdom",
Usando o aplicativo Vue Weather , vamos ver alguns exemplos para testar componentes Vue.
Vamos pular direto para um exemplo de um arquivo de teste de unidade no Vue! O primeiro arquivo de teste de unidade é encontrado em src/components/__tests__/WeatherHeader.spec.js e testa o WeatherHeader
componente:
import { describe, it, expect } from 'vitest'
import { shallowMount } from '@vue/test-utils'
import WeatherHeader from '../WeatherHeader.vue'
describe('WeatherHeader.vue Test', () => {
it('renders message when component is created', () => {
// render the component
const wrapper = shallowMount(WeatherHeader, {
propsData: {
title: 'Vue Project'
}
})
// check that the title is rendered
expect(wrapper.text()).toMatch('Vue Project')
})
})
A primeira linha neste arquivo importa as funções de teste do Vitest que são usadas neste arquivo.
Se você quiser que a API Vitest esteja disponível globalmente (como o Jest funciona), adicione
test: {globals: true}
adefineConfig()
função em vite.config.js . Para mais detalhes, confira a documentação do Vitest .
A segunda linha neste arquivo importa uma função chamada shallowMount
da biblioteca Vue Test Utils. A ideia de 'montagem' significa o carregamento de um componente individual para poder testá-lo. Existem dois métodos para isso no Vue Test Utils:
shallowMount()
- cria um wrapper
para o componente Vue, mas com componentes filhos stubbedmount()
- cria um wrapper
para o componente Vue, incluindo a montagem de qualquer componente filhoComo nosso foco é testar um componente individual (o WeatherHeader
componente), usaremos shallowMount()
.
shallowMount()
é melhor para testar um componente individual isoladamente, pois os componentes filhos são stubs. Esta é a situação ideal para testes unitários .Além disso, usar
shallowMount()
para testar um componente com muitos componentes filho pode melhorar o tempo de execução do teste de unidade, pois não há custo (em termos de tempo) para renderizar os componentes filhos.
mount()
é útil quando você deseja incluir o teste do comportamento dos componentes filho.
A terceira linha importa o componente Vue que será testado, WeatherHeader.vue .
Após as import
instruções, há um describe
bloco que define um conjunto de testes de unidade.
Dentro de um arquivo de teste de unidade, pode haver vários describe
blocos que definem diferentes conjuntos de testes de unidade. Da mesma forma, cada describe
bloco pode conter vários testes de unidade, onde cada teste de unidade é definido por um it
bloco.
Considero essa distinção como:
describe
bloco - suíte de teste de unidadeit
bloco - função de teste de unidade individualO que é bom sobre o teste de unidade com o Vitest é que existem vários incentivos embutidos para adicionar comentários. Por exemplo, o primeiro argumento para describe
deve explicar claramente qual componente Vue está sendo testado:
describe('WeatherHeader.vue Test', () => { ... })
Para cada it
bloco, o primeiro argumento é uma descrição da função de teste, que deve ser uma breve descrição do que esse teste específico está fazendo. No exemplo acima, o it
bloco testa se o componente 'renderiza a mensagem quando o componente é criado'.
Quanto ao teste unitário real, o primeiro passo é montar o componente Vue para que possa ser testado:
// render the component
const wrapper = shallowMount(WeatherHeader, {
propsData: {
title: 'Vue Project'
}
})
A shallowMount
função retorna um wrapper
objeto, que contém o componente montado e os métodos para testar esse componente. O wrapper
objeto nos permite testar todos os aspectos do HTML gerado pelo componente Vue e todas as propriedades (como dados) do componente Vue.
Além disso, as props, passadas para o WeatherHeader
componente, são passadas como o segundo argumento para shallowMount()
.
A verificação real realizada no teste de unidade é:
// check that the title is rendered
expect(wrapper.text()).toMatch('Vue Project')
Esta linha serve wrapper
para verificar se o título gerado pelo componente é 'Vue Project'. Como essa verificação faz uma comparação de strings, é recomendável usar toMatch()
.
Enquanto as verificações no arquivo de teste de unidade para o WeatherHeader
componente estão apenas verificando valores de string, existem [muitas opções disponíveis no Vitest para realizar verificações:
toBeTruthy()
- verifica se uma variável/instrução é verdadeiratoBeFalsy()
- verifica se uma variável/instrução é falsatoBeNull()
- verifica se uma variável corresponde apenas a nulltoBeUndefined()
- verifica se uma variável não está definidatoBeDefined()
- verifica se uma variável está definidatoBeGreaterThan()
- verifica se um número é maior que o valor especificadotoBeGreaterThanOrEqual()
- verifica se um número é maior ou igual ao valor especificadotoBeLessThan()
- verifica se um número é menor que o valor especificadotoBeLessThanOrEqual()
- verifica se um número é menor ou igual ao valor especificadotoBe()
e toEqual()
- verifica se um número é igual ao valor especificado (essas funções são equivalentes para números)toBeCloseTo()
- verifica se um número é igual ao valor especificado dentro de uma pequena tolerância (útil para números de ponto flutuante)toMatch()
- verifica se uma string é igual ao valor especificado (Regex pode ser usado como o valor especificado!)toContain()
- verifica se um array contém o valor especificadoAlém disso, o not
qualificador pode ser usado com a maioria destas verificações:
expect(wrapper.text()).not.toMatch('Node Project')
Para obter uma lista completa de verificações disponíveis, confira a referência da API Vitest .
Este exemplo mostra como testar as condições iniciais (ou estado) do WeatherResult
componente.
Aqui está um esboço do arquivo de teste de unidade (definido em src/components/__tests__/WeatherResult.spec.js ):
import { describe, it, expect, beforeEach, afterEach } from 'vitest'
import { shallowMount, flushPromises } from '@vue/test-utils'
import WeatherResult from '@/components/WeatherResult.vue'
describe('WeatherResult.vue Implementation Test', () => {
let wrapper = null
// SETUP - run before to each unit test
beforeEach(() => {
// render the component
wrapper = shallowMount(WeatherResult, {
propsData: {
city: '',
weatherSummary: '',
weatherDescription: '',
currentTemperature: 0.0,
lowTemperature: 0.0,
highTemperature: 0.0
}
})
})
// TEARDOWN - run after to each unit test
afterEach(() => {
wrapper.unmount()
})
it('initializes with correct elements', () => { ... })
it('processes valid props data', async () => { ... })
it('emits a custom event when the Clear Weather Data button is clicked', () => { ... })
})
O arquivo de teste de unidade utiliza a shallowMount()
função para renderizar o WeatherResult
componente, pois esse componente é testado como um componente individual isoladamente.
Dentro do conjunto de testes de unidade (definido dentro do describe
bloco), existem duas novas funções definidas:
beforeEach()
- chamado antes da execução de cada teste de unidade dentro deste conjunto de testes de unidadeafterEach()
- chamado após a execução de cada teste de unidade dentro deste conjunto de testes de unidadeA beforeEach()
função é usada para definir um estado consistente antes de executar cada teste de unidade. Esse conceito é muito importante para garantir que a ordem de execução dos testes unitários não afete os resultados dos testes unitários como um todo.
Neste exemplo, a beforeEach()
função renderiza o componente com um conjunto padrão de dados de prop:
// SETUP - run before to each unit test
beforeEach(() => {
// render the component
wrapper = shallowMount(WeatherResult, {
propsData: {
city: '',
weatherSummary: '',
weatherDescription: '',
currentTemperature: 0.0,
lowTemperature: 0.0,
highTemperature: 0.0
}
})
})
A afterEach()
função é usada para limpar qualquer processamento realizado durante o teste de unidade.
Neste exemplo, a afterEach()
função desmonta o wrapper
usado durante o teste de unidade, para que wrapper
possa ser reinicializado para o próximo teste de unidade no beforeEach()
:
// TEARDOWN - run after to each unit test
afterEach(() => {
wrapper.unmount()
})
Se você deseja executar o código que é executado antes ou depois da execução do conjunto geral de testes de unidade, você pode usar:
beforeAll(() => {
/* Runs before all tests */
})
afterAll(() => {
/* Runs after all tests */
})
O primeiro teste de unidade verifica as condições iniciais do WeatherResult
componente:
it('initializes with correct elements', () => {
// check that the heading text is rendered
expect(wrapper.findAll('h2').length).toEqual(2)
expect(wrapper.findAll('h2').at(0).text()).toMatch('Weather Summary')
expect(wrapper.findAll('h2').at(1).text()).toMatch('Temperatures')
// check that 6 fields of data for the temperature are displayed
expect(wrapper.findAll('p').length).toEqual(6)
expect(wrapper.findAll('p').at(0).text()).toMatch('City:')
expect(wrapper.findAll('p').at(1).text()).toMatch('Summary:')
expect(wrapper.findAll('p').at(2).text()).toMatch('Details:')
expect(wrapper.findAll('p').at(3).text()).toMatch('Current: 0° F')
expect(wrapper.findAll('p').at(4).text()).toMatch('High (Today): 0° F')
expect(wrapper.findAll('p').at(5).text()).toMatch('Low (Today): 0° F')
})
Verificações:
expect
s verifica se os dois cabeçalhos (definidos como h2
elementos) estão conforme o esperado.expect
s verifica se os seis campos de dados (definidos como p
elementos) estão conforme o esperado.O segundo teste de unidade verifica se os dados válidos passados como dados prop são tratados corretamente pelo WeatherResult
componente:
it('processes valid props data', async () => {
// Update the props passed in to the WeatherResult component
wrapper.setProps({
city: 'Chicago',
weatherSummary: 'Cloudy',
weatherDescription: 'Cloudy with a chance of rain',
currentTemperature: 45.1,
lowTemperature: 42.0,
highTemperature: 47.7
})
// Wait until the DOM updates
await flushPromises()
// check that the prop data is stored as expected within the component
expect(wrapper.vm.city).toMatch('Chicago')
expect(wrapper.vm.weatherSummary).toMatch('Cloudy')
expect(wrapper.vm.weatherDescription).toMatch('Cloudy with a chance of rain')
expect(wrapper.vm.currentTemperature).toEqual(45.1)
expect(wrapper.vm.lowTemperature).toBeCloseTo(42.0)
expect(wrapper.vm.highTemperature).toBe(47.7)
// check that the heading text is rendered
expect(wrapper.findAll('h2').length).toEqual(2)
expect(wrapper.findAll('h2').at(0).text()).toMatch('Weather Summary')
expect(wrapper.findAll('h2').at(1).text()).toMatch('Temperatures')
// check that 6 fields of data for the temperature are displayed
expect(wrapper.findAll('p').length).toEqual(6)
expect(wrapper.findAll('p').at(0).text()).toMatch('City: Chicago')
expect(wrapper.findAll('p').at(1).text()).toMatch('Summary: Cloudy')
expect(wrapper.findAll('p').at(2).text()).toMatch('Details: Cloudy with a chance of rain')
expect(wrapper.findAll('p').at(3).text()).toMatch('Current: 45.1° F')
expect(wrapper.findAll('p').at(4).text()).toMatch('High (Today): 47.7° F')
expect(wrapper.findAll('p').at(5).text()).toMatch('Low (Today): 42° F')
})
Como a beforeEach()
função fornece um conjunto padrão de dados de prop, precisamos substituir os dados de prop usando a setProps()
função.
Para garantir que os dados do prop causem as atualizações esperadas no WeatherResult
, o teste precisa aguardar que todas as atualizações do DOM entrem em vigor:
// Wait until the DOM updates
await flushPromises()
NOTA: O uso de
await
só é possível se a função for definida comasync
!
Verificações:
WeatherResult
componente verificando os elementos de dados (usando wrapper.vm
).expect
s verifica se os dois cabeçalhos (definidos como h2
elementos) estão conforme o esperado.expect
s verifica se os dados da prop são usados para definir os seis campos de dados (definidos como p
elementos) conforme o esperado.O terceiro teste de unidade verifica se o clear-weather-data
evento é emitido pelo WeatherResult
componente quando o usuário clica no botão 'Clear Weather Data':
it('emits a custom event when the Clear Weather Data button is clicked', () => {
// trigger an event when the 'Clear Weather Data' button is clicked
wrapper.findAll('button').at(0).trigger('click')
// check that 1 occurrence of the event has been emitted
expect(wrapper.emitted('clear-weather-data')).toBeTruthy()
expect(wrapper.emitted('clear-weather-data').length).toBe(1)
})
Para acionar um evento de clique, o button
elemento deve ser encontrado no wrapper
e então a trigger
função é chamada para acionar o evento de clique.
Uma vez que o botão é clicado, o teste de unidade verifica se apenas um evento personalizado (com o nome de clear-weather-data
) é emitido.
Dentro do App
componente, quando um usuário pesquisa o clima de uma cidade, uma chamada HTTP GET é feita para o Open Weather para recuperar os dados por meio de uma biblioteca de terceiros chamada Axios :
const searchCity = (inputCity) => {
// GET request for user data
axios.get('http://api.openweathermap.org/data/2.5/weather?q=' + inputCity + '&units=imperial&APPID=' + openweathermapApiKey.value)
.then((response) => {
// handle success
console.log(response)
weatherData.value.city = response.data.name
weatherData.value.weatherSummary = response.data.weather[0].main
weatherData.value.weatherDescription = response.data.weather[0].description
weatherData.value.currentTemperature = response.data.main.temp
weatherData.value.lowTemperature = response.data.main.temp_min
weatherData.value.highTemperature = response.data.main.temp_max
validWeatherData.value = true
})
.catch((error) => {
// handle error
messageType.value = 'Error'
messageToDisplay.value = 'ERROR! Unable to retrieve weather data for ' + inputCity + '!'
console.log(error.message)
resetData()
})
.finally((response) => {
// always executed
console.log('HTTP GET Finished!')
})
}
Ao pensar em como testar as chamadas HTTP GET, dois cenários vêm à mente, cada um testando o efeito colateral da chamada real da API:
Ao testar o código que utiliza uma API externa, geralmente é mais fácil não fazer a chamada real, substituindo a chamada por uma simulação. Existem prós e contras nessa abordagem, no entanto.
Prós:
Contras:
Em algum momento, você deve verificar a integração completa para garantir que a forma da resposta da API não foi alterada.
Como este artigo é focado em testes de unidade, vamos zombar da biblioteca Axios.
A simulação fornece um meio de imitar o comportamento esperado de um módulo de software. Embora o mocking possa ser usado no código de produção (muito perigoso!), normalmente é usado durante o desenvolvimento e teste.
O carregamento de dados de uma API externa leva tempo. Embora normalmente leve menos de um ou dois segundos para carregar os dados do Open Weather neste aplicativo, outras APIs externas podem consumir mais tempo. Além disso, queremos uma maneira de verificar facilmente se a solicitação HTTP GET falha. Portanto, adicionaremos simulações para especificar como a solicitação GET responderia.
Os testes de unidade para o App
componente estão localizados no arquivo src/components/__tests__/App.spec.js .
Para começar, precisamos import
da biblioteca Axios:
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
import { shallowMount, mount, flushPromises } from '@vue/test-utils'
import App from '../../App.vue'
import axios from 'axios'
No entanto, não queremos usar a biblioteca Axios real como é feito no código-fonte ( App.vue ). Em vez disso, queremos criar uma simulação da biblioteca Axios para que não chamemos a API externa:
// Mock the axios library
vi.mock("axios", () => {
return {
default: {
get: vi.fn(),
},
};
});
Este bloco de código diz ao Vitest que o get()
método dentro da axios
biblioteca deve ser simulado.
No arquivo de teste de unidade ( src/components/__tests__/App.spec.js ), para o App
componente, temos:
Para começar, vamos lidar com a situação nominal em que a solicitação HTTP GET é bem-sucedida.
describe('Implementation Test for App.vue with Successful HTTP GET', () => {
let wrapper = null
beforeEach(() => {
const responseGet = { data:
{
name: 'Chicago',
weather: [
{
main: 'Cloudy',
description: 'Cloudy with a chance of rain'
}
],
main: {
temp: 56.3,
temp_min: 53.8,
temp_max: 58.6
}
}
}
// Set the mock call to GET to return a successful GET response
axios.get.mockResolvedValue(responseGet)
// render the component
wrapper = shallowMount(App)
})
afterEach(() => {
axios.get.mockReset()
wrapper.unmount()
})
...
})
Na beforeEach()
função, definimos a resposta que deve ocorrer quando axios.get()
for chamado. A resposta são os dados meteorológicos pré-enlatados que se parecem com o que obtemos do Open Weather, se realmente fizermos a solicitação. A linha chave nesta seção é:
// Set the mock call to GET to return a successful GET response
axios.get.mockResolvedValue(responseGet)
Esta linha é a chave, pois permite ao Vitest saber que deve retornar o responseGet
array quando axios.get()
for chamado no App
componente, em vez de realmente fazer uma chamada HTTP GET usando o Axios.
A próxima seção do conjunto de testes de unidade define a afterEach()
função:
afterEach(() => {
axios.get.mockReset()
wrapper.unmount()
})
A afterEach()
função, que é chamada após a execução de cada teste de unidade, limpa a simulação axios.get()
que foi criada durante a execução do teste de unidade. Essa abordagem é uma boa prática para limpar quaisquer simulações após a execução de um teste, para que todos os testes subsequentes comecem a partir de um estado conhecido.
Agora podemos definir o teste de unidade:
it('does load the weather data when a successful HTTP GET occurs', async () => {
wrapper.vm.searchCity('Chicago')
// Wait until the DOM updates
await flushPromises()
expect(axios.get).toHaveBeenCalledTimes(1)
expect(axios.get).toBeCalledWith(expect.stringMatching(/Chicago/))
// check that the user data is properly set
expect(wrapper.vm.weatherData.city).toMatch('Chicago')
expect(wrapper.vm.weatherData.weatherSummary).toMatch('Cloudy')
expect(wrapper.vm.weatherData.weatherDescription).toMatch('Cloudy with a chance of rain')
expect(wrapper.vm.weatherData.currentTemperature).toEqual(56.3)
expect(wrapper.vm.weatherData.lowTemperature).toEqual(53.8)
expect(wrapper.vm.weatherData.highTemperature).toEqual(58.6)
expect(wrapper.vm.validWeatherData).toBe(true)
})
Como já passamos pelas etapas de definição do mock e renderização do componente (via shallowMount()
), este teste de unidade pode se concentrar em realizar verificações.
O teste de unidade começa chamando a searchCity()
função:
wrapper.vm.searchCity('Chicago')
Para garantir que a searchCity()
função cause as atualizações esperadas no App
componente, o teste precisa aguardar que todas as Promises sejam resolvidas e que as atualizações do DOM entrem em vigor:
// Wait until all Promises are resolved and the DOM updates
await flushPromises()
Verificamos que axios.get()
foi chamado apenas uma vez e que a chamada HTTP GET incluiu o nome correto da cidade:
expect(axios.get).toHaveBeenCalledTimes(1)
expect(axios.get).toBeCalledWith(expect.stringMatching(/Chicago/))
Para ser muito completo, os dados meteorológicos também verificam a instância do App
componente renderizado neste teste de unidade para garantir que ele corresponda aos dados pré-enlatados retornados da simulação de axios.get()
:
// check that the user data is properly set
expect(wrapper.vm.weatherData.city).toMatch('Chicago')
expect(wrapper.vm.weatherData.weatherSummary).toMatch('Cloudy')
expect(wrapper.vm.weatherData.weatherDescription).toMatch('Cloudy with a chance of rain')
expect(wrapper.vm.weatherData.currentTemperature).toEqual(56.3)
expect(wrapper.vm.weatherData.lowTemperature).toEqual(53.8)
expect(wrapper.vm.weatherData.highTemperature).toEqual(58.6)
expect(wrapper.vm.validWeatherData).toBe(true)
Embora seja bom testar quando as coisas acontecem conforme o esperado, também é importante verificar como nosso software reage a condições negativas. Com isso em mente, vamos criar um segundo conjunto de testes de unidade para verificar uma solicitação HTTP GET com falha:
describe('Implementation Test for App.vue with Failed HTTP GET', () => { ... })
Não há problema em ter vários conjuntos de testes de unidade em um único arquivo de teste de unidade ( .spec.js ).
Como os mocks são criados na
beforeEach()
função, é necessário haver conjuntos de testes de unidade separados combeforeEach()
implementações diferentes para respostas HTTP GET bem-sucedidas e com falha.
A beforeEach()
função neste conjunto de testes de unidade é bem diferente:
beforeEach(() => {
// Set the mock call to GET to return a failed GET request
axios.get.mockRejectedValue(new Error('BAD REQUEST'))
// Render the component
wrapper = shallowMount(App)
})
Em vez de definir uma resposta para retornar da axios.get()
chamada, agora estamos retornando um Promise
objeto com falha com a resposta de 'BAD REQUEST'.
A afterEach()
função para este conjunto de testes de unidade é idêntica ao outro conjunto de testes de unidade:
afterEach(() => {
axios.get.mockReset()
wrapper.unmount()
})
Aqui está a função de teste de unidade para testar uma solicitação HTTP GET com falha:
it('does not load the weather data when a failed HTTP GET occurs', async () => {
wrapper.vm.searchCity('Chicago')
expect(axios.get).toHaveBeenCalledTimes(1)
expect(axios.get).toBeCalledWith(expect.stringMatching(/Chicago/))
// Wait until the DOM updates
await flushPromises()
// Check that there is no user data loaded when the GET request fails
expect(wrapper.vm.weatherData.city).toMatch(/^$/)
expect(wrapper.vm.weatherData.weatherSummary).toMatch(/^$/)
expect(wrapper.vm.weatherData.weatherDescription).toMatch(/^$/)
expect(wrapper.vm.weatherData.currentTemperature).toEqual(0)
expect(wrapper.vm.weatherData.lowTemperature).toEqual(0)
expect(wrapper.vm.weatherData.highTemperature).toEqual(0)
expect(wrapper.vm.validWeatherData).toBe(false)
// check that the banner message indicates failure
expect(wrapper.vm.messageToDisplay).toMatch('ERROR! Unable to retrieve weather data for Chicago!')
expect(wrapper.vm.messageType).toMatch('Error')
})
Assim como no conjunto de testes de unidade anterior, verificamos se apenas uma instância de axios.get()
é chamada e, em seguida, verificamos se nenhum dado climático foi carregado no App
componente.
Ao desenvolver testes de unidade, pode ser bom entender quanto do código-fonte é realmente testado. Esse conceito é conhecido como cobertura de código.
Preciso deixar bem claro que ter um conjunto de testes de unidade que cobrem 100% do código-fonte não é de forma alguma um indicador de que o código foi testado adequadamente.
Essa métrica significa que há muitos testes de unidade e muito esforço foi feito para desenvolver os testes de unidade. A qualidade dos testes unitários ainda precisa ser verificada por inspeção de código.
O outro extremo onde este é um conjunto mínimo (ou nenhum!) de testes de unidade é um indicador muito ruim.
Vitest fornece cobertura de código usando o --coverage
sinalizador.
Para executar facilmente o Vitest com resultados de cobertura, gosto de incluir os seguintes itens na script
seção de package.json :
{
"name": "vue-weather-app",
"version": "1.0.0",
"scripts": {
...
"test:unit": "vitest run --environment jsdom",
"test:coverage": "vitest run --environment jsdom --coverage",
"test:ui": "vitest --environment jsdom --coverage --ui"
},
...
}
Quando npm run test:unit
é executado, os testes de unidade são executados:
$ npm run test:unit
...
✓ src/components/__tests__/WeatherBanner.spec.js (5)
✓ src/components/__tests__/WeatherSearch.spec.js (5)
✓ src/components/__tests__/WeatherFooter.spec.js (1)
✓ src/components/__tests__/WeatherHeader.spec.js (1)
✓ src/components/__tests__/WeatherResult.spec.js (3)
✓ src/components/__tests__/App.spec.js (7)
Test Files 6 passed (6)
Tests 22 passed (22)
Time 2.81s (in thread 536ms, 524.89%)
Quando npm run test:coverage
executado, os testes de unidade são executados e a cobertura é relatada:
$ npm run test:coverage
...
Test Files 6 passed (6)
Tests 22 passed (22)
Time 3.38s (in thread 660ms, 512.10%)
--------------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
--------------------|---------|----------|---------|---------|-------------------
All files | 99.15 | 96.55 | 100 | 99.15 |
src | 97.31 | 85.71 | 100 | 97.31 |
App.vue | 97.31 | 85.71 | 100 | 97.31 | 60-63
src/components | 100 | 100 | 100 | 100 |
WeatherBanner.vue | 100 | 100 | 100 | 100 |
WeatherFooter.vue | 100 | 100 | 100 | 100 |
WeatherHeader.vue | 100 | 100 | 100 | 100 |
WeatherResult.vue | 100 | 100 | 100 | 100 |
WeatherSearch.vue | 100 | 100 | 100 | 100 |
--------------------|---------|----------|---------|---------|-------------------
O npm run test:ui
carregará os resultados do teste e da cobertura em seu navegador da Web padrão, o que pode ser conveniente para ver visualmente onde está faltando a cobertura do teste.
Depois de passar por vários arquivos de teste de unidade diferentes, recomendo a seguinte estrutura para o arquivo de teste de unidade para um componente Vue:
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
import { shallowMount } from '@vue/test-utils'
import App from '@/App.vue' // Import Vue component to test
import axios from 'axios' // Import libraries to mock
// Mock the axios library
vi.mock("axios", () => {
return {
default: {
get: vi.fn(),
},
};
});
describe('Tests for the ... Component', () => {
let wrapper = null
beforeEach(() => {
// set any initial data and create the mocks of libraries
// render the component
wrapper = shallowMount(App)
})
afterEach(() => {
axios.get.mockReset()
wrapper.unmount()
})
it('check successful events', () => { ... })
it('check failure events', () => { ... })
})
Itens chave:
beforeEach()
e afterEach()
para criar funções de teste de unidade independentesbeforeEach()
função e atualize os dados da prop nas funções de teste de unidadeshallowMount()
over mount()
para se concentrar em testar componentes individuaisEste artigo fornece um guia para testes de unidade de componentes Vue, com foco em:
Simplificando, ao considerar o que testar, concentre-se em testar as entradas e saídas (resultados reais), não a lógica de negócios subjacente (como os resultados são produzidos). Com isso em mente, reserve um ou dois minutos para revisar os exemplos novamente, anotando as entradas e saídas testadas.
Fonte: https://testdrive.io
1596754901
The shift towards microservices and modular applications makes testing more important and more challenging at the same time. You have to make sure that the microservices running in containers perform well and as intended, but you can no longer rely on conventional testing strategies to get the job done.
This is where new testing approaches are needed. Testing your microservices applications require the right approach, a suitable set of tools, and immense attention to details. This article will guide you through the process of testing your microservices and talk about the challenges you will have to overcome along the way. Let’s get started, shall we?
Traditionally, testing a monolith application meant configuring a test environment and setting up all of the application components in a way that matched the production environment. It took time to set up the testing environment, and there were a lot of complexities around the process.
Testing also requires the application to run in full. It is not possible to test monolith apps on a per-component basis, mainly because there is usually a base code that ties everything together, and the app is designed to run as a complete app to work properly.
Microservices running in containers offer one particular advantage: universal compatibility. You don’t have to match the testing environment with the deployment architecture exactly, and you can get away with testing individual components rather than the full app in some situations.
Of course, you will have to embrace the new cloud-native approach across the pipeline. Rather than creating critical dependencies between microservices, you need to treat each one as a semi-independent module.
The only monolith or centralized portion of the application is the database, but this too is an easy challenge to overcome. As long as you have a persistent database running on your test environment, you can perform tests at any time.
Keep in mind that there are additional things to focus on when testing microservices.
Test containers are the method of choice for many developers. Unlike monolith apps, which lets you use stubs and mocks for testing, microservices need to be tested in test containers. Many CI/CD pipelines actually integrate production microservices as part of the testing process.
As mentioned before, there are many ways to test microservices effectively, but the one approach that developers now use reliably is contract testing. Loosely coupled microservices can be tested in an effective and efficient way using contract testing, mainly because this testing approach focuses on contracts; in other words, it focuses on how components or microservices communicate with each other.
Syntax and semantics construct how components communicate with each other. By defining syntax and semantics in a standardized way and testing microservices based on their ability to generate the right message formats and meet behavioral expectations, you can rest assured knowing that the microservices will behave as intended when deployed.
It is easy to fall into the trap of making testing microservices complicated, but there are ways to avoid this problem. Testing microservices doesn’t have to be complicated at all when you have the right strategy in place.
There are several ways to test microservices too, including:
What’s important to note is the fact that these testing approaches allow for asynchronous testing. After all, asynchronous development is what makes developing microservices very appealing in the first place. By allowing for asynchronous testing, you can also make sure that components or microservices can be updated independently to one another.
#blog #microservices #testing #caylent #contract testing #end-to-end testing #hoverfly #integration testing #microservices #microservices architecture #pact #testing #unit testing #vagrant #vcr
1598685221
In this tutorial, I will show you how to upload a file in Vue using vue-dropzone library. For this example, I am using Vue.js 3.0. First, we will install the Vue.js using Vue CLI, and then we install the vue-dropzone library. Then configure it, and we are ready to accept the file. DropzoneJS is an open source library that provides drag and drops file uploads with image previews. DropzoneJS is lightweight doesn’t depend on any other library (like jQuery) and is highly customizable. The vue-dropzone is a vue component implemented on top of Dropzone.js. Let us start Vue File Upload Using vue-dropzone Tutorial.
Dropzone.js is an open-source library providing drag-and-drop file uploads with image previews. DropzoneJS is lightweight, doesn’t depend on any other library (like jQuery), and is highly customizable.
The vue-dropzone is a vue component implemented on top of Dropzone.js.
First, install the Vue using Vue CLI.
Go to your terminal and hit the following command.
npm install -g @vue/cli
or
yarn global add @vue/cli
If you face any error, try running the command as an administrator.
Now, we need to generate the necessary scaffold. So type the following command.
vue create vuedropzone
It will install the scaffold.
Open the project in your favorite editor. Mine is Visual Studio Code.
cd vuedropzone
code .
I am using the Yarn package manager. So let’s install using Yarn. You can use NPM, also. It does not matter.
yarn add vue2-dropzone
or
npm install vue2-dropzone
Okay, now we need to add one css file with the above package. Now, vue cli uses css loader, so we can directly import in the src >> main.js entry file.
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
render: h => h(App)
}).$mount('#app')
import 'vue2-dropzone/dist/vue2Dropzone.css'
If importing css is not working for you, then you need to install that CSS file manually.
Copy this vue2Dropzone.css file’s content.
Create one file inside the src >> assets folder, create one css file called vuedropzone.css and paste the content there.
Import this css file inside src >> App.vue file.
<style lang="css">
@import './assets/vuedropzone.css';
</style>
Now, it should include in our application.
Our primary boilerplate has one ready-made component called HelloWorld.vue inside src >> components folder. Now, create one more file called FileUpload.vue.
Add the following code to FileUpload.vue file.
// FileUpload.vue
<template>
<div id="app">
<vue-dropzone id="upload" :options="config"></vue-dropzone>
</div>
</template>
<script>
import vueDropzone from "vue2-dropzone";
export default {
data: () => ({
config: {
url: "https://appdividend.com"
}
}),
components: {
vueDropzone
}
};
</script>
Here, our API endpoint is https://appdividend.com. It is the point where we will hit the POST route and store our image, but it is my blog’s homepage, so it will not work anyway. But let me import this file into App.vue component and see what happens.
// App.vue
<template>
<div id="app">
<FileUpload />
</div>
</template>
<script>
import FileUpload from './components/FileUpload.vue'
export default {
name: 'app',
components: {
FileUpload
}
}
</script>
<style lang="css">
@import './assets/vuedropzone.css';
</style>
Now, start the development server using the following command. It will open up URL: http://localhost:8080.
npm run serve
Now, after uploading the image, we can see that the image upload is failed due to the wrong POST request endpoint.
Install the Laravel.
After that, we configure the database in the .env file and use MySQL database.
We need to create one model and migration file to store the image. So let us install the following command inside the Laravel project.
php artisan make:model Image -m
It will create both the Image model and create_images_table.php migrations file.
Now, open the migrations file and add the schema to it.
// create_images_table.php
public function up()
{
Schema::create('images', function (Blueprint $table) {
$table->increments('id');
$table->string('image_name');
$table->timestamps();
});
}
Now, migrate the database table using the following command.
php artisan migrate
It creates the table in the database.
Now, we need to add a laravel-cors package to prevent cross-site-allow-origin errors. Go to the Laravel root and enter the following command to install it.
composer require barryvdh/laravel-cors
Configure it in the config >> app.php file.
Barryvdh\Cors\ServiceProvider::class,
Add the middleware inside app >> Http >> Kernel.php file.
// Kernel.php
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
\App\Http\Middleware\TrustProxies::class,
\Barryvdh\Cors\HandleCors::class,
];
First, create an ImageController.php file using the following command.
php artisan make:controller ImageController
Define the store method. Also, create one images folder inside the public directory because we will store an image inside it.
Right now, I have written the store function that handles one image at a time. So do not upload multiple photos at a time; otherwise, it will break.
// ImageController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Image;
class ImageController extends Controller
{
public function store(Request $request)
{
if($request->file('file'))
{
$image = $request->file('file');
$name = time().$image->getClientOriginalName();
$image->move(public_path().'/images/', $name);
}
$image= new Image();
$image->image_name = $name;
$image->save();
return response()->json(['success' => 'You have successfully uploaded an image'], 200);
}
}
Go to the routes >> api.php file and add the following route.
// api.php
Route::post('image', 'ImageController@store');
We need to add the correct Post request API endpoint in FileUpload.vue component.
// FileUpload.vue
<template>
<div id="app">
<vue-dropzone id="drop1" :options="config" @vdropzone-complete="afterComplete"></vue-dropzone>
</div>
</template>
<script>
import vueDropzone from "vue2-dropzone";
export default {
data: () => ({
config: {
url: "http://localhost:8000/api/image",
}
}),
components: {
vueDropzone
},
methods: {
afterComplete(file) {
console.log(file);
}
}
};
</script>
Now, save the file and try to upload an image. If everything is okay, then you will be able to save the image on the Laravel web server as well as save the name in the database as well.
You can also verify on the server side by checking the database entry and the images folder in which we have saved the image.
The only required options are url, but there are many more you can use.
For example, let’s say you want:
export default {
data: () => ({
dropOptions: {
url: "https://httpbin.org/post",
maxFilesize: 5, // MB
maxFiles: 5,
chunking: true,
chunkSize: 400, // Bytes
thumbnailWidth: 100, // px
thumbnailHeight: 100,
addRemoveLinks: true
}
})
// ...
}
Happy Coding !!!
Originally published at https://appdividend.com
#vue #vue-dropzone #vue.js #dropzone.js #dropzonejs #vue cli
1620983255
Automation and segregation can help you build better software
If you write automated tests and deliver them to the customer, he can make sure the software is working properly. And, at the end of the day, he paid for it.
Ok. We can segregate or separate the tests according to some criteria. For example, “white box” tests are used to measure the internal quality of the software, in addition to the expected results. They are very useful to know the percentage of lines of code executed, the cyclomatic complexity and several other software metrics. Unit tests are white box tests.
#testing #software testing #regression tests #unit tests #integration tests