Com as muitas ferramentas disponíveis para auxiliar no desenvolvimento AngularJS aplicações, muitas pessoas têm a impressão de que é uma estrutura extremamente complicada, o que não é o caso. Esse é um dos principais motivos pelos quais comecei esta série de tutoriais.
Dentro parte um cobrimos os fundamentos da estrutura AngularJS e começamos escrevendo nosso primeiro aplicativo. Esta postagem é destinada a iniciantes. Se você é mais desenvolvedor AngularJS experiente , você pode estar mais interessado em desmistificando diretivas ou uma história de AngularJS em uso em uma startup em crescimento .
Neste tutorial, vamos deixar de lado a camada de lógica do aplicativo e aprender como conduzir a configuração adequada do projeto AngularJS, incluindo andaime, gerenciamento de dependência e prepará-lo para teste (unidade e ponta a ponta). Faremos isso usando estas ferramentas AngularJS: Yeoman, Grunt e Bower. Em seguida, revisaremos o processo de escrever e executar testes Jasmine usando Karma.
Se você trabalha com JavaScript, é altamente provável que já conheça pelo menos algumas dessas ferramentas, mesmo que seja novo no Angular . Mas para ajudar a garantir uma linha de base comum, evitarei fazer suposições. Vamos revisar rapidamente cada uma dessas tecnologias e para que elas são úteis:
Carma (anteriormente conhecido como Testacular) é o executor de teste de JavaScript do Google e a escolha natural para testar o AngularJS. Além de permitir que você execute seus testes em navegadores reais (incluindo navegadores de telefone / tablet), também é teste de framework agnóstico ; o que significa que você pode usá-lo em conjunto com qualquer estrutura de teste de sua escolha (como Jasmine, Mocha , ou QUnit , entre outros).
Jasmim será nosso framework de teste de escolha, pelo menos para este post. Sua sintaxe é bastante semelhante à de RSpec , se você já trabalhou com isso. (Se não o fez, não se preocupe; verificaremos com mais detalhes posteriormente neste tutorial.)
Terra é um executor de tarefas que ajuda a automatizar várias tarefas repetitivas, como minificação , compilação (ou construção), teste e configuração de uma visualização de seu aplicativo AngularJS.
Bower é um gerenciador de pacotes que o ajuda a localizar e instalar todas as dependências do seu aplicativo, como estruturas CSS, bibliotecas JavaScript e assim por diante. É executado no git, bem como Empacotador Rails e evita a necessidade de baixar e atualizar manualmente as dependências.
Yeoman é um conjunto de ferramentas que contém 3 componentes principais: Grunt, Bower e a ferramenta de andaime Eu . Yo gera código clichê com a ajuda de geradores (que são apenas modelos de estrutura) e configura automaticamente o Grunt e o Bower para o seu projeto. Você pode encontrar geradores para quase qualquer estrutura JavaScript (Angular, Backbone, Ember, etc.), mas como estamos focando aqui no Angular, usaremos o gerador angular projeto.
Bem, a primeira coisa que precisamos fazer é instalar as ferramentas de que precisaremos.
Se você não tem ir , node.js e acima do nível do mar já instalado, vá em frente e instale-os.
Em seguida, iremos para a linha de comando e executaremos o seguinte comando para instalar as ferramentas do Yeoman:
npm install -g yo grunt-cli bower
Ah, e não se esqueça, vamos usar o gerador AngularJS, então você também precisará instalá-lo:
npm install -g generator-angular
OK, agora estamos prontos para ...
Última vez , pegamos emprestado manualmente nosso código padrão do semente angular projeto. Desta vez, vamos deixar yo (em conjunto com o gerador angular) fazer isso por nós.
Tudo o que precisamos fazer é criar nossa nova pasta de projeto, navegar até ela e executar:
yo angular
Seremos apresentados a algumas opções, como incluir ou não Bootstrap e Bússola . Por enquanto, digamos não para bússola e sim para o Bootstrap. Então, quando questionado sobre quais módulos incluir (recurso, cookies, sanitizar e rota), selecionaremos apenas angular-route.js
.
Nosso scaffold de projeto agora deve ser criado (pode demorar um minuto), integrado ao Karma e tudo pré-configurado.
Nota: Lembre-se de que estamos restringindo os módulos aqui aos que usamos no aplicativo que construímos parte um deste tutorial. Quando você estiver fazendo isso para seu próprio projeto, caberá a você determinar quais módulos você precisará incluir.
Agora, como usaremos Jasmine, vamos adicionar o karma-jasmine
adaptador para nosso projeto:
npm install karma-jasmine --save-dev
No caso de desejarmos que nossos testes sejam executados em uma instância do Chrome, vamos adicionar também o karma-chrome-launcher
:
npm install karma-chrome-launcher --save-dev
OK, se fizemos tudo certo, nossa árvore de arquivos de projeto agora deve ter a seguinte aparência:
Nosso código de aplicativo estático vai para o app/
e o diretório test/
O diretório conterá (sim, você adivinhou!) nossos testes. Os arquivos que vemos na raiz são os arquivos de configuração do nosso projeto. Há muito a ser aprendido sobre cada um deles, mas por enquanto vamos ficar apenas com a configuração padrão. Então, vamos executar nosso aplicativo pela primeira vez, o que podemos fazer simplesmente com o seguinte comando:
grunt serve
E voila! Nosso aplicativo agora deve aparecer na nossa frente!
Antes de entrar na parte realmente importante (ou seja, o teste), vamos reservar um minuto para aprender um pouco mais sobre Bower . Como mencionado anteriormente, Bower é nosso gerenciador de pacotes. Adicionar uma lib ou plugin ao nosso projeto pode simplesmente ser feito usando o bower install
comando. Por exemplo, para incluir modernizr
, tudo o que precisamos fazer é o seguinte (dentro do diretório do nosso projeto, é claro):
bower install modernizr
Observe, entretanto, que embora isso faça modernizr
parte do nosso projeto (estará localizado no diretório app/bower_components
), ainda somos responsáveis por incluí-lo em nosso aplicativo (ou gerenciando quando deve ser incluído) como precisaríamos fazer com qualquer lib adicionada manualmente. Uma maneira de fazer isso seria simplesmente adicionar a seguinte tag ao nosso index.html
:
bower.json
Como alternativa, podemos usar o bower.json
arquivo para gerenciar nossas dependências. Depois de seguir cuidadosamente todas as etapas até agora, o { 'name': 'F1FeederApp', 'version': '0.0.0', 'dependencies': { 'angular': '1.2.15', 'json3': '~3.2.6', 'es5-shim': '~2.1.0', 'jquery': '~1.11.0', 'bootstrap': '~3.0.3', 'angular-route': '1.2.15' }, 'devDependencies': { 'angular-mocks': '1.2.15', 'angular-scenario': '1.2.15' } }
arquivo deve ser parecido com este:
bower install
A sintaxe é bastante autoexplicativa, mas há mais informações disponíveis Aqui .
Podemos então adicionar quaisquer novas dependências que quisermos e, então, tudo o que precisamos é o seguinte comando para instalá-las:
app
OK, agora é hora de realmente começar de onde paramos em parte um e escrever alguns testes para nosso aplicativo AngularJS.
Mas, primeiro, há um pequeno problema que precisamos resolver: embora os desenvolvedores de gerador angular baseou seu modelo de projeto no semente angular (que é o boilerplate oficial Angular), por alguma razão que eu realmente não entendo, eles decidiram mudar o css
convenções de nomenclatura de pastas (alterando styles
para js
, scripts
para tests/spec/controllers
e assim por diante).
Como resultado, o aplicativo que escrevemos originalmente agora tem caminhos que são inconsistentes com o scaffold que acabamos de gerar. Para contornar isso, vamos baixar o código do aplicativo em Aqui e trabalhar com essa versão a partir deste ponto (é basicamente o mesmo aplicativo que escrevemos originalmente, mas com os caminhos atualizados para corresponder à nomenclatura angular do gerador).
Depois de baixar o aplicativo, navegue até drivers.js
pasta e crie um arquivo chamado describe('Controller: driversController', function () { // First, we load the app's module beforeEach(module('F1FeederApp')); // Then we create some variables we're going to use var driversController, scope; beforeEach(inject(function ($controller, $rootScope, $httpBackend) { // Here, we create a mock scope variable, to replace the actual $scope variable // the controller would take as parameter scope = $rootScope.$new(); // Then we create an $httpBackend instance. I'll talk about it below. httpMock = $httpBackend; // Here, we set the httpBackend standard reponse to the URL the controller is // supposed to retrieve from the API httpMock.expectJSONP( 'http://ergast.com/api/f1/2013/driverStandings.json?callback=JSON_CALLBACK').respond( {'MRData': {'StandingsTable': {'StandingsLists' : [{'DriverStandings':[ { 'Driver': { 'givenName': 'Sebastian', 'familyName': 'Vettel' }, 'points': '397', 'nationality': 'German', 'Constructors': [ {'name': 'Red Bull'} ] }, { 'Driver': { 'givenName': 'Fernando', 'familyName': 'Alonso' }, 'points': '242', 'nationality': 'Spanish', 'Constructors': [ {'name': 'Ferrari'} ] }, { 'Driver': { 'givenName': 'Mark', 'familyName': 'Webber' }, 'points': '199', 'nationality': 'Australian', 'Constructors': [ {'name': 'Red Bull'} ] } ]}]}}} ); // Here, we actually initialize our controller, passing our new mock scope as parameter driversController = $controller('driversController', { $scope: scope }); // Then we flush the httpBackend to resolve the fake http call httpMock.flush(); })); // Now, for the actual test, let's check if the driversList is actually retrieving // the mock driver array it('should return a list with three drivers', function () { expect(scope.driversList.length).toBe(3); }); // Let's also make a second test checking if the drivers attributes match against // the expected values it('should retrieve the family names of the drivers', function () { expect(scope.driversList[0].Driver.familyName).toBe('Vettel'); expect(scope.driversList[1].Driver.familyName).toBe('Alonso'); expect(scope.driversList[2].Driver.familyName).toBe('Webber'); }); });
contendo o seguinte:
driverscontroller
Este é o conjunto de testes para nosso describe()
. Pode parecer muito código, mas a maior parte é, na verdade, apenas uma simulação de declaração de dados. Vamos dar uma olhada rápida nos elementos realmente importantes:
it()
método define nosso conjunto de testes.beforeEach()
é uma especificação de teste adequada.$httpBackend
função é executada imediatamente antes de cada um dos testes.O elemento mais importante (e potencialmente confuso) aqui é o httpMock
serviço que instanciamos no expectJSONP()
variável. Este serviço atua como um back-end falso e responde às nossas chamadas de API nas execuções de teste, assim como nosso servidor real faria na produção. Nesse caso, usando expect()
, nós a configuramos para interceptar quaisquer solicitações JSONP para o URL fornecido (o mesmo que usamos para obter as informações do servidor) e, em vez disso, retornar uma lista estática com três drivers, imitando a resposta real do servidor. Isso nos permite saber com certeza o que deve voltar do controlador. Podemos, portanto, comparar os resultados com os esperados, usando grunt test
função. Se eles corresponderem, o teste será aprovado.
A execução dos testes é feita simplesmente com o comando:
drivercontroller
O conjunto de testes para o controlador de detalhes do driver (generator-angular
) deve ser bastante semelhante ao que acabamos de ver. Eu recomendo que você tente descobrir por si mesmo como um exercício (ou você pode apenas dar uma olhada Aqui , se você não estiver em condições).
A equipe Angular introduziu recentemente um novo corredor para testes de ponta a ponta chamado Transferidor . Usa webdriver para interagir com o aplicativo em execução no navegador e também usa a estrutura de teste Jasmine por padrão, de modo que a sintaxe será altamente consistente com a de nossos testes de unidade.
Porém, como o Protractor é uma ferramenta relativamente nova, é integração com a pilha do Yeoman e yo
ainda requer uma boa quantidade de trabalho de configuração. Com isso em mente, e minha intenção de manter este tutorial o mais simples possível, meu plano é dedicar um post futuro exclusivamente para cobrir testes de ponta a ponta em AngularJS em profundidade.
Neste ponto da série de tutoriais, aprendemos como fazer o scaffold de nosso aplicativo Angular com bower
, gerenciar suas dependências com karma
e escrever / executar alguns testes usando protractor
e
|_+_|. Lembre-se, porém, de que este tutorial é apenas uma introdução a essas ferramentas e práticas do AngularJS; não analisamos nenhum deles aqui em grande profundidade.
Nosso objetivo foi simplesmente ajudá-lo a iniciar este caminho. A partir daqui, depende de você prosseguir e aprender tudo o que puder sobre esta incrível estrutura e conjunto de ferramentas.
Depois de ler este tutorial, algumas pessoas podem perguntar: 'Esperar. Você não deveria fazer tudo isso antes de realmente começar a codificar seu aplicativo? Isso não deveria ter sido a primeira parte deste tutorial? ”
Minha resposta curta para isso é não . Como vimos na parte um, você não precisa saber tudo isso para codificar seu primeiro aplicativo Angular. Em vez disso, a maioria das ferramentas que discutimos nesta postagem são projetadas para ajudá-lo a otimizar seu fluxo de trabalho de desenvolvimento e praticar o Desenvolvimento Orientado a Testes (TDD).
E por falar em TDD, o conceito mais básico de TDD certamente é sólido; ou seja, escreva seus testes antes de escrever seu código. Algumas pessoas, porém, levam esse conceito longe demais. TDD é uma prática de desenvolvimento, não um método de aprendizagem. Adequadamente, escrevendo seus testes antes de escrever seu código faz muito sentido, enquanto aprendendo como escrever seus testes antes de aprender a codificar não.
Eu pessoalmente acho que esta é a principal razão pela qual os tutoriais oficiais do Angular podem parecer tão complicados e podem ser quase impossíveis de seguir para pessoas sem experiência anterior em MVC / TDD front-end. Essa é uma das principais razões pelas quais iniciei esta série de tutoriais.
Meu conselho pessoal para aqueles que estão aprendendo a navegar no mundo AngularJS é: não seja muito duro consigo mesmo. Você não precisa aprender tudo de uma vez (apesar das pessoas dizerem o contrário!). Dependendo de sua experiência anterior com outras estruturas de front-end / teste, AngularJS pode ser muito difícil de entender inicialmente. Portanto, aprenda tudo o que você precisa aprender até que seja capaz de escrever seus próprios aplicativos simples e, em seguida, uma vez que se sinta confortável com os princípios básicos da estrutura, você pode se preocupar em selecionar e aplicar as práticas de desenvolvimento de longo prazo que funcionam melhor para você.
Claro, essa é minha humilde opinião e nem todos concordarão com essa abordagem (e a equipe de desenvolvimento do Angular pode enviar um assassino contratado atrás de mim assim que eu publicar isso), mas essa é minha visão e tenho certeza de que muitas pessoas lá fora quem vai concordar comigo.
Relacionado: Tutorial do Angular 6: novos recursos com novo poder