Testando projetos Node.js. Parte 1. Anatomia e tipos de teste

O autor do material, a primeira parte da tradução que publicamos hoje, diz que, como consultor independente do Node.js, analisa mais de 10 projetos por ano. Seus clientes, o que é bastante justificado, pedem que ele preste atenção especial aos testes. Alguns meses atrás, ele começou a fazer anotações sobre técnicas valiosas de teste e os erros que encontrou. O resultado foi um material contendo três dezenas de recomendações para testes.

imagem

Em particular, ele se concentrará na seleção de tipos de teste adequados para uma situação específica, no design adequado, na avaliação de sua eficácia e onde exatamente nas cadeias de CI / CD você precisará colocá-los. Alguns dos exemplos aqui são ilustrados usando Jest, outros usando Mocha. Este material é focado principalmente não em ferramentas, mas em metodologia de teste.

Testando projetos Node.js. Parte 2. Avaliação do desempenho do teste, integração contínua e análise da qualidade do código

▍0. Regra de ouro: os testes devem ser muito simples e diretos


Você conhece alguém - um amigo, um membro da família, o herói do filme, que está sempre carregado de bom humor e sempre pronto para oferecer uma mãozinha sem exigir nada em troca? É assim que bons testes devem ser projetados. Eles devem ser simples, devem ser benéficos e evocam emoções positivas. Isso pode ser alcançado pela seleção cuidadosa de métodos, ferramentas e objetivos de teste. Aqueles cujo uso justifica o tempo e o esforço despendidos na preparação e realização de testes e, ao mesmo tempo, produz bons resultados. Você só precisa testar o que precisa ser testado, deve se esforçar para garantir que os testes sejam simples e flexíveis e, às vezes, pode recusar alguns testes, sacrificando significativamente a confiabilidade do projeto por sua simplicidade e velocidade de desenvolvimento.

Os testes não devem ser considerados como código de aplicativo normal. O fato é que uma equipe típica envolvida no desenvolvimento de um projeto, em qualquer caso, faz todo o possível para mantê-lo em condições de trabalho, ou seja, se esforça para, digamos, um produto comercial para funcionar como seus usuários esperam. Como resultado, essa equipe pode não estar muito feliz por ter que apoiar mais um "projeto" complexo, representado por um conjunto de testes. Se os testes do código principal crescerem, chamando cada vez mais atenção para si mesmos e se tornando motivo de preocupação constante, então o trabalho neles será abandonado ou, tentando manter um nível decente, fornecerá tanto tempo e energia que isso retardará o trabalho no projeto principal.

Portanto, o código de teste deve ser o mais simples possível, com um número mínimo de dependências e níveis de abstração. Os testes devem ter uma aparência para que possam ser entendidos rapidamente. A maioria das recomendações que consideraremos aqui decorre desse princípio.

Seção 1. Anatomia dos testes


▍1 Crie seus testes para que o relatório informe o que está sendo testado, em que cenário e o que é esperado dos testes


Recomendações


O relatório de teste deve indicar se a versão atual do aplicativo atende a seus requisitos. Isso deve ser feito de uma forma que seja compreensível para aqueles que não precisam estar familiarizados com o código do aplicativo. Pode ser um testador, um especialista em DevOps que está implantando o projeto ou o próprio desenvolvedor, que analisou o projeto algum tempo depois de escrever seu código. Isso pode ser alcançado se, ao escrever testes, se concentrar nos requisitos do produto. Com essa abordagem, a estrutura do teste pode ser imaginada consistindo em três partes:

  1. O que exatamente está sendo testado? Por exemplo, o método ProductsService.addNewProduct .
  2. Em que cenário e em que circunstâncias o teste é realizado? Por exemplo, a reação do sistema é verificada em uma situação em que o preço das mercadorias não foi repassado ao método.
  3. Quais são os resultados esperados do teste? Por exemplo, em uma situação semelhante, o sistema se recusa a confirmar a adição de um novo produto a ele.

Consequências do desvio das recomendações


Suponha que o sistema não possa ser implantado e, a partir do relatório de teste, você pode descobrir apenas que ele não passou no teste chamado Add product , que verifica a adição de um determinado produto a ele. Isso fornecerá informações sobre o que exatamente deu errado?

Abordagem correta


As informações de teste consistem em três informações.

 //1.   describe('Products Service', function() { //2.  describe('Add new product', function() {   // 3. ,       it('When no price is specified, then the product status is pending approval', ()=> {     const newProduct = new ProductService().add(...);     expect(newProduct.status).to.equal('pendingApproval');   }); }); }); 

Abordagem correta


O relatório de teste é semelhante a um documento que contém uma declaração de requisitos do produto.

Veja como fica em diferentes níveis.


Documento de Requisitos do Produto, Nomeação de Teste, Resultados do Teste

  1. Um documento com requisitos do produto pode ser, de fato, um documento especial ou pode existir na forma de algo como um email.
  2. Ao nomear testes, descrevendo o objetivo dos testes, seu cenário e os resultados esperados, você precisa aderir ao idioma usado para formular os requisitos do produto. Isso o ajudará a comparar o código de teste e os requisitos do produto.
  3. Os resultados dos testes devem ser claros, mesmo para aqueles que não estão familiarizados com o código do aplicativo ou que o esqueceram completamente. Esses são testadores, especialistas em DevOps, desenvolvedores voltando a trabalhar com o código alguns meses depois de escrevê-lo.

§ 2 Descreva o que você espera dos testes no idioma do produto: use instruções no estilo BDD


Recomendações


O desenvolvimento de testes em estilo declarativo permite que aqueles que trabalham com eles compreendam instantaneamente sua essência. Se os testes são escritos usando uma abordagem imperativa, eles são preenchidos com construções condicionais que complicam bastante sua compreensão. Seguindo esse princípio, as expectativas devem ser descritas em uma linguagem próxima do comum. O estilo declarativo do BDD usa construções expect or should , em vez de algum código especial de seu próprio design. Se não há instruções necessárias no Chai ou no Jest, e acontece que tais declarações geralmente são necessárias, considere adicionar novas "verificações" ao Jest ou escrever seus próprios plugins para o Chai .

Consequências do desvio das recomendações


Se você não seguir as recomendações descritas acima, isso acabará com o fato de que os membros da equipe de desenvolvimento escreverão menos testes e ignorarão as verificações irritantes usando o método .skip() .

Abordagem incorreta


O leitor deste teste terá que revisar completamente o código imperativo bastante longo apenas para entender o que exatamente está sendo testado no teste.

 it("When asking for an admin, ensure only ordered admins in results" , ()={   //,       — "admin1"  "admin2",   "user1"   const allAdmins = getUsers({adminOnly:true});   const admin1Found, adming2Found = false;   allAdmins.forEach(aSingleUser => {       if(aSingleUser === "user1"){           assert.notEqual(aSingleUser, "user1", "A user was found and not admin");       }       if(aSingleUser==="admin1"){           admin1Found = true;       }       if(aSingleUser==="admin2"){           admin2Found = true;       }   });   if(!admin1Found || !admin2Found ){       throw new Error("Not all admins were returned");   } }); 

Abordagem correta


Você pode literalmente entender esse teste rapidamente.

 it("When asking for an admin, ensure only ordered admins in results" , ()={   //,        const allAdmins = getUsers({adminOnly:true});     expect(allAdmins).to.include.ordered.members(["admin1" , "admin2"]) .but.not.include.ordered.members(["user1"]); }); 

▍3 Realize testes de código de teste usando plug-ins especiais


Recomendações


Há um conjunto de plug-ins para ESLint projetado especificamente para analisar o código de teste e para encontrar problemas nesse código. Por exemplo, o plug-in eslint-plugin-mocha emitirá avisos se o teste for escrito no nível global (e não for um descendente de describe() ), ou se os testes forem ignorados , o que pode dar falsas esperanças de que todos os testes sejam aprovados. O plugin eslint-plugin-jest funciona de maneira semelhante, por exemplo, alertando sobre testes que não possuem instruções, ou seja, sobre aqueles que não verificam nada.

Consequências do desvio das recomendações


O desenvolvedor ficará feliz em ver que o código é coberto em 90% nos testes e 100% dos testes passam com êxito. No entanto, ele permanecerá nesse estado apenas até que muitos testes, de fato, não verifiquem nada e alguns scripts de teste sejam simplesmente ignorados. Só podemos esperar que ninguém implante projetos que sejam "testados" dessa maneira na produção.

Abordagem incorreta


O cenário de teste está cheio de erros que, felizmente, podem ser detectados usando o linter.

 describe("Too short description", () => { const userToken = userService.getDefaultToken() // *error:no-setup-in-describe, use hooks (sparingly) instead it("Some description", () => {});//* error: valid-test-description. Must include the word "Should" + at least 5 words }); it.skip("Test name", () => {// *error:no-skipped-tests, error:error:no-global-tests. Put tests only under describe or suite expect("somevalue"); // error:no-assert }); it("Test name", () => {*//error:no-identical-title. Assign unique titles to tests }); 

▍4 Atenha-se ao método da caixa preta - teste apenas métodos públicos


Recomendações


Testar alguns mecanismos de código interno significa um aumento significativo na carga dos desenvolvedores e quase não traz benefícios. Se uma determinada API produz os resultados corretos, vale a pena gastar várias horas testando seus mecanismos internos e, em seguida, ainda dando suporte a esses testes, que facilmente quebram, atualizados? Ao testar métodos publicamente disponíveis, sua implementação interna, embora implicitamente, também é verificada. Esse teste causará um erro se surgir um problema no sistema, o que resulta na emissão de dados incorretos. Essa abordagem também é chamada de "teste comportamental". Por outro lado, testando os mecanismos internos de uma determinada API (ou seja, usando a técnica de "caixa branca"), o desenvolvedor se concentra nos pequenos detalhes da implementação e não no resultado final do código. Testes que verificam tais sutilezas podem começar a gerar erros, por exemplo, após uma pequena refatoração de código, mesmo que o sistema continue produzindo resultados corretos. Como resultado, essa abordagem aumenta significativamente a carga no programador associado ao suporte ao código de teste.

Consequências do desvio das recomendações


Os testes que tentam capturar os mecanismos internos de um determinado sistema se comportam como um pastor de uma fábula que chamava camponeses com gritos de “Socorro! Lobo! ”Quando não havia lobo por perto. As pessoas correram para o auxílio apenas para descobrir que haviam sido enganadas. E quando o lobo realmente apareceu, ninguém veio em socorro. Esses testes produzem resultados falsos positivos, por exemplo, nos casos em que os nomes de algumas variáveis ​​internas mudam. Como resultado, não é de surpreender que quem realiza esses testes logo comece a ignorar seus "gritos", o que, em última análise, leva ao fato de que uma vez que um erro realmente sério pode passar despercebido.

Abordagem incorreta


Este teste testa os mecanismos internos de uma classe sem motivo específico para essas verificações.

 class ProductService{ //      //     ,      calculateVAT(priceWithoutVAT){   return {finalPrice: priceWithoutVAT * 1.2};   //           } //  getPrice(productId){   const desiredProduct= DB.getProduct(productId);   finalPrice = this.calculateVATAdd(desiredProduct.price).finalPrice; } } it("White-box test: When the internal methods get 0 vat, it return 0 response", async () => {   //       VAT,      .  ,   ,        expect(new ProductService().calculateVATAdd(0).finalPrice).to.equal(0); }); 

▍5. Escolha os objetos de backup apropriados: evite mobs, preferindo stubs e spies


Recomendações


O uso do teste dobra quando o teste é um mal necessário, pois eles estão associados aos mecanismos internos do aplicativo. Sem alguns deles, é simplesmente impossível. Aqui está um material útil sobre este tópico. No entanto, várias abordagens para o uso de tais objetos não podem ser chamadas de equivalentes. Portanto, alguns deles - stubs (stub) e spies (espiões), visam testar os requisitos do produto, mas, como um efeito colateral inevitável, são forçados a afetar levemente os mecanismos internos desse produto. As zombarias, por outro lado, têm como objetivo testar os mecanismos internos do projeto. Portanto, seu uso leva a uma carga desnecessária enorme nos programadores, sobre os quais falamos acima, oferecendo aderência à metodologia da "caixa preta" ao escrever testes.

Antes de usar objetos duplicados, faça uma pergunta simples: “Eu os uso para testar a funcionalidade descrita ou ela pode ser descrita nos requisitos técnicos do projeto?”. Se a resposta a esta pergunta for negativa, isso pode significar que você testará o produto usando a abordagem de "caixa branca", sobre a qual já falamos sobre as deficiências.

Por exemplo, se você deseja descobrir se seu aplicativo funciona corretamente em uma situação em que um serviço de pagamento não está disponível, você pode interromper esse serviço e fazer com que o aplicativo receba algo indicando que não há resposta. Isso permitirá que você verifique a reação do sistema a uma situação semelhante, para descobrir se ele se comporta corretamente. No decorrer desse teste, é feita uma verificação do comportamento, resposta ou resultado da aplicação em determinadas condições. Nessa situação, você pode usar o espião para verificar se, ao detectar uma queda no serviço de pagamento, um determinado email foi enviado. Isso, novamente, será uma verificação do comportamento do sistema em uma determinada situação, que, com certeza, está registrada nos requisitos técnicos, por exemplo, da seguinte forma: "Envie um email ao administrador se o pagamento não for aprovado". Por outro lado, se você usar um objeto simulado para representar um serviço de pagamento e verificar o trabalho ao acessá-lo com a transferência do que ele espera dele, falaremos sobre o teste de mecanismos internos que não estão diretamente relacionados à funcionalidade do aplicativo e, bastante talvez possa mudar com frequência.

Consequências do desvio das recomendações


Com qualquer refatoração de código, você terá que procurar todos os moki, refatoração e seu código. Como resultado, o suporte a testes se tornará um fardo pesado, tornando-os inimigos do desenvolvedor, não de seus amigos.

Abordagem incorreta


Este exemplo mostra um objeto simulado focado em testar os mecanismos internos do aplicativo.

 it("When a valid product is about to be deleted, ensure data access DAL was called once, with the right product and right config", async () => {   //,        const dataAccessMock = sinon.mock(DAL);   // ,           dataAccessMock.expects("deleteProduct").once().withArgs(DBConfig, theProductWeJustAdded, true, false);   new ProductService().deletePrice(theProductWeJustAdded);   mock.verify(); }); 

Abordagem correta


Os espiões têm como objetivo testar os sistemas quanto à conformidade com seus requisitos, mas, como efeito colateral, inevitavelmente afetam os mecanismos internos dos sistemas.

 it("When a valid product is about to be deleted, ensure an email is sent", async () => {   //,        const spy = sinon.spy(Emailer.prototype, "sendEmail");   new ProductService().deletePrice(theProductWeJustAdded);   //  .       ? ,               (  ) }); 

§ 6 Durante o teste, use dados realistas, não limitados a algo como "foo"


Recomendações


Muitas vezes, os erros de produção se manifestam em uma combinação de circunstâncias muito específica e até surpreendente. E isso significa que, quanto mais próximos da realidade dos dados de entrada usados ​​durante o teste, maior a probabilidade de detecção precoce de erros. Use para gerar dados semelhantes a bibliotecas especializadas reais, como o Faker . Por exemplo, essas bibliotecas geram números de telefone aleatórios, mas realistas, nomes de usuários, números de cartões bancários, nomes de empresas e até textos de "lorem ipsum". Além disso, considere usar dados de ambientes de produção em testes. Se você deseja levar esses testes para um nível ainda mais alto, consulte nossa próxima recomendação sobre testes baseados em propriedades.

Consequências do desvio das recomendações


Ao testar um projeto durante o seu desenvolvimento, todos os testes podem ser aprovados somente se forem realizados usando dados irreais, como as linhas "foo". Mas, na produção, o sistema falhará em uma situação em que o hacker fornece algo como @3e2ddsf . ##' 1 fdsfds . fds432 AAAA @3e2ddsf . ##' 1 fdsfds . fds432 AAAA @3e2ddsf . ##' 1 fdsfds . fds432 AAAA .

Abordagem incorreta


O sistema passa com êxito nesses testes apenas porque eles usam dados irrealistas.

 const addProduct = (name, price) =>{ const productNameRegexNoSpace = /^\S*$/;//  if(!productNameRegexNoSpace.test(name))   return false;// , -   ,  .     //  -    return true; }; it("Wrong: When adding new product with valid properties, get successful confirmation", async () => {   // "Foo",    ,    ,    false   const addProductResult = addProduct("Foo", 5);   expect(addProductResult).to.be.true;   // :     - ,     //         }); 

Abordagem correta


Ele usa dados aleatórios semelhantes aos dados reais.

 it("Better: When adding new valid product, get successful confirmation", async () => {   const addProductResult = addProduct(faker.commerce.productName(), faker.random.number());   //   : {'Sleek Cotton Computer',  85481}   expect(addProductResult).to.be.true;   //  ,         ,    .   //     ,    ! }); 

▍ 7. Sistemas de teste usando várias combinações de entradas usando testes baseados em propriedades


Recomendações


Normalmente, os testes usam pequenos conjuntos de dados de entrada. Mesmo que se assemelhem a dados reais (falamos sobre isso na seção anterior), esses testes abrangem apenas um número muito limitado de combinações possíveis de entradas da entidade investigada. Por exemplo, pode ser assim: (method('', true, 1), method("string" , false" , 0)) . O problema é que, na API de produção, chamada com cinco parâmetros, é possível obter a entrada de milhares de variantes diferentes de suas combinações, uma das quais pode levar a uma falha (seria apropriado recordar a difusão aqui ). E se você pudesse escrever um único teste que verifique automaticamente um determinado método para 1000 combinações de suas entradas e descubra qual O método responde incorretamente? O teste com base na verificação de propriedades é exatamente o que -nos em tal situação é útil. Ou seja, no curso deste módulo de teste verifica, chamando-o com todas as combinações possíveis de dados de entrada, o que aumenta a probabilidade de encontrar alguns bugs. Suponha que temos um método addNewProduct(id, name, isDiscount) e Biblioteca realizando testes, chama-o com muitas combinações de parâmetros de tipo numérico, string e lógico, por exemplo - (1, "iPhone", false) , (2, "Galaxy", true) . É possível realizar testes com base na verificação de propriedades usando o ambiente de execução de testes usual (Mocha, Jest etc.) e usando bibliotecas especializadas como js-verifica ou testcheck (esta biblioteca possui uma documentação muito boa).

Consequências do desvio das recomendações


Inconscientemente, o desenvolvedor seleciona esses dados de teste que cobrem apenas as partes do código que funcionam corretamente. Infelizmente, isso reduz a eficácia dos testes como forma de detectar erros.

Abordagem correta


Testando muitas opções de entrada usando a biblioteca mocha-testcheck.

 require('mocha-testcheck').install(); const {expect} = require('chai'); const faker = require('faker'); describe('Product service', () => { describe('Adding new', () => {   //  100         check.it('Add new product with random yet valid properties, always successful',     gen.int, gen.string, (id, name) => {       expect(addNewProduct(id, name).status).to.equal('approved');     }); }) }); 

▍8. Esforce-se para que o código de teste seja auto-suficiente, minimizando auxílios externos e abstrações


Recomendações


Provavelmente agora é óbvio que estou comprometido com testes extremamente simples. O fato é que, caso contrário, a equipe de desenvolvimento de um determinado projeto, de fato, precisa lidar com outro projeto. Para entender seu código, eles precisam gastar um tempo valioso, o que não tem muito. Está muito bem escrito sobre esse fenômeno: “Um código de produção de alta qualidade é um código bem pensado e um código de teste de alta qualidade é um código completamente compreensível ... Ao escrever um teste, pense em quem verá a mensagem de erro exibida por ele. Essa pessoa não gostaria, para entender as causas do erro, ler o código de todo o conjunto de testes ou o código da árvore de herança dos utilitários usados ​​para o teste. "

Para que o leitor entenda o teste sem deixar seu código, minimize o uso de utilitários, ganchos ou quaisquer mecanismos externos ao executar o teste. Se, para fazer isso, você precisa recorrer e colar códigos com muita frequência, pode parar em um mecanismo auxiliar externo, cuja utilização não violará a compreensibilidade do teste. Porém, se o número desses mecanismos aumentar, o código de teste perderá a compreensão.

Consequências do desvio das recomendações


, 4 , 2 , ? ! , , .


. ?

 test("When getting orders report, get the existing orders", () => {   const queryObject = QueryHelpers.getQueryObject(config.DBInstanceURL);   const reportConfiguration = ReportHelpers.getReportConfig();//   ?        userHelpers.prepareQueryPermissions(reportConfiguration);//  ?         const result = queryObject.query(reportConfiguration);   assertThatReportIsValid();//  ,           -    expect(result).to.be.an('array').that.does.include({id:1, productd:2, orderStatus:"approved"});   //      ?        }) 

Abordagem correta


, .

 it("When getting orders report, get the existing orders", () => {   // ,           const orderWeJustAdded = ordersTestHelpers.addRandomNewOrder();   const queryObject = newQueryObject(config.DBInstanceURL, queryOptions.deep, useCache:false);   const result = queryObject.query(config.adminUserToken, reports.orders, pageSize:200);   expect(result).to.be.an('array').that.does.include(orderWeJustAdded); }) 

▍9. :


Recomendações


, , , , . . , ( ) . — , ( , ). — , , , , . , , . — , , , , ( , , , ).

Consequências do desvio das recomendações


, . . . . , , , .


. , .

 before(() => { //       .   ? - ,  -   json-. await DB.AddSeedDataFromJson('seed.json'); }); it("When updating site name, get successful confirmation", async () => { // ,  ,  "Portal", ,           const siteToUpdate = await SiteService.getSiteByName("Portal"); const updateNameResult = await SiteService.changeName(siteToUpdate, "newName"); expect(updateNameResult).to.be(true); }); it("When querying by site name, get the right site", async () => { // ,  ,  "Portal", ,           const siteToCheck = await SiteService.getSiteByName("Portal"); expect(siteToCheck.name).to.be.equal("Portal"); //!      :[ }); 

Abordagem correta


, , .

 it("When updating site name, get successful confirmation", async () => { //           const siteUnderTest = await SiteService.addSite({   name: "siteForUpdateTest" }); const updateNameResult = await SiteService.changeName(siteUnderTest, "newName"); expect(updateNameResult).to.be(true); }); 

▍10. , . expect


Recomendações


, , try-catch-finally catch . , , , .

Chai, expect(method).to.throw . Jest: expect(method).toThrow() . , . , , .

Consequências do desvio das recomendações


, , , .


, try-catch .

 it("When no product name, it throws error 400", async() => { let errorWeExceptFor = null; try { const result = await addNewProduct({name:'nest'});} catch (error) { expect(error.code).to.equal('InvalidInput'); errorWeExceptFor = error; } expect(errorWeExceptFor).not.to.be.null; //    ,         //  ,     null,       }); 

Abordagem correta


expect , , .

 it.only("When no product name, it throws error 400", async() => { expect(addNewProduct)).to.eventually.throw(AppError).with.property('code', "InvalidInput"); }); 

▍11. ,


Recomendações


. , (smoke test), -, , . - . , , , #cold , #api , #sanity . . , Mocha -g ( --grep ).

Consequências do desvio das recomendações


, , , , , , . .

Abordagem correta


#cold-test , . , -, , — .

 //    ( ,    ),     // ,        //   describe('Order service', function() { describe('Add new order #cold-test #sanity', function() {   it('Scenario - no currency was supplied. Expectation - Use the default currency #sanity', function() {     //-    }); }); }); 

▍12.


Recomendações


, Node.js-. , , Node.js .

TDD — , , . , . , , Red-Green-Refactor . , - , , , , , . , . ( — , , ).

Consequências do desvio das recomendações


— , . .

2.


▍13. ,


Recomendações


, , 10 , . , . , . , (, ), , , , ? - ?

, . , 2019 , , TDD, — , . , , , . , IoT-, , , - Kafka RabbitMQ, . - , , , . , , , , ? (, , Alexa) , , .

, ( ). , , , , , , . , , - API — Consumer-Driven Contracts . , , , , . , , , , , . , , .

, TDD . , TDD , . , , , .

Consequências do desvio das recomendações


— ( ), .

Abordagem correta


. . , , Node.js, .

▍14. ,


Recomendações


. — . , , . , , - , , - ? , . , : TDD, — .

«». API, - , (, , , , , ). , , , (, ). , , , , , , .

Consequências do desvio das recomendações


, , , , 20.

Abordagem correta


supertest , API, Express, .


API, Express

▍15. , API, Consumer-Driven Contracts


Recomendações


, , , , . , , - , , , - . «-22» : . , , . , Consumer-Driven Contracts PACT .

. . PACT , ( «»). , , PACT, , , . , , , , .

Consequências do desvio das recomendações


.

Abordagem correta



Consumer-Driven Contracts

, , B , . B .

▍16.


Recomendações


(middleware) - , , - , Express-. . , , . , , JS- {req,res} . , «» (, Sinon ) , {req,res} . , , , . node-mock-http , , , . , , HTTP-, -.

Consequências do desvio das recomendações


Express .

Abordagem correta


Express-.

 // ,     const unitUnderTest = require('./middleware') const httpMocks = require('node-mocks-http'); //  Jest,     Mocha    describe()  it() test('A request without authentication header, should return http status 403', () => { const request = httpMocks.createRequest({   method: 'GET',   url: '/user/42',   headers: {     authentication: ''   } }); const response = httpMocks.createResponse(); unitUnderTest(request, response); expect(response.statusCode).toBe(403); }); 

▍17.


Recomendações


, , , , , , . , , - . , , , ( , , ), , ( — ) . , : SonarQube ( 2600 GitHub) Code Climate ( 1500 ).

Consequências do desvio das recomendações


, , . . , .

Abordagem correta


Code Climate.


Code Climate

▍18. , Node.js


Recomendações


, , . , , , - , . , - , , , , ? , , ? , API ?

Netflix - . , , , , . , - — Chaos Monkey . , , , . Kubernetes — kube-monkey . , Node.js? , , , V8 1.7 . . node-chaos , -.

Consequências do desvio das recomendações


, , , .

Abordagem correta


npm- chaos-monkey , Node.js.


chaos-monkey

Sumário


, Node.js-. , . .

Caros leitores! - ?

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


All Articles