Compreendendo o Angular: injeção de dependências e testes
Não há nada de especial e difícil sobre injeção de dependência e testes com Angular. Você só precisa se acostumar com a sintaxe.
Quando eu comecei a aprender sobre testes de aplicações em Angular↳Angular30 conteúdosCriando Micro Frontends Angular com Native FederationDev (Back & Front) · mar 2026Angular v21 e o Fim da Cobertura de Testes Exclusivamente em TypeScript: Por Que Precisamos Repensar os Testes de ComponentesDev (Back & Front) · jan 2026Angular 8 é lançado com builder APIs e suporte web workerDev (Back & Front) · mai 2019Ver tudo em Dev (Back & Front) →, eu achei surpreendentemente difícil de entender. Em particular, eu continuei preso na estranha sintaxe que era necessária para configurar as dependências de teste.
Como se vê, não há nada de especial e difícil sobre injeção de dependência e testes com Angular. Você só precisa se acostumar com a sintaxe. Uma maneira de fazer isso é fingir que é outra coisa. Permitam-me explicar.
Teste com Angular no modo fácil (mas inexistente)
Vamos imaginar que estamos escrevendo um aplicativo Pastry Shop. Nosso aplicativo precisa de um serviço para fazer bolos, que chamaremos de Baker. O serviço Baker requer algumas coisas para fazer o seu trabalho. Por exemplo, ele precisa ter acesso a uma Store (loja) onde se pode obter os ingredientes necessários. Ele também precisa de um Mixer (batedeira) e um Oven (forno). Em outras palavras, ele tem certas dependências.
Agora, vamos imaginar que estamos usando uma versão especial do JavaScript, que torna mais fácil expressar as dependências usando anotações. É assim que o nosso serviço Baker pode parecer:
@inject(Store, Mixer, Oven)
function Baker() {
var bake = function(item) {
if (item === 'vanilla cake') {
var ingredients = [
Store.get('sugar'),
Store.get('flower'),
Store.get('eggs')
];
var dough = Mixer.mix(ingredients);
var cake = Oven.cook(dough);
cake.frosting = 'vanilla';
return cake;
};
};
return: {
bake: bake
};
};
Estamos usando uma anotação chamada @inject para especificar que Baker precisa de Store, Mixer e Oven para fazer o seu trabalho. Essa mesma anotação poderia ser usada para escrever os testes correspondentes:
@inject(Baker, Store, Mixer, Oven)
describe('Baker Service tests', function () {
it('should bake vanilla cake', function () {
// arrange
spyOn(Store, 'get').andReturnValue({});
spyOn(Mixer, 'mix').andReturnValue({});
spyOn(Oven, 'cook').andReturnValue({});
// act
var cake = Baker.bake('cake');
// assert
expect(Store.get).toHaveBeenCalledWith('sugar');
expect(Store.get).toHaveBeenCalledWith('flower');
expect(Store.get).toHaveBeenCalledWith('baking soda');
expect(Store.get).toHaveBeenCalledWith('eggs');
expect(Mixer.mix).toHaveBeenCalled();
expect(Oven.cook).toHaveBeenCalled();
expect(cake.frosting).toEqual('vanilla');
});
});
Teste com Angular no modo (menos) fácil (mas realmente possível)
Infelizmente, o código acima não vai funcionar em JavaScript. A boa notícia é que o Angular nos oferece várias maneiras de fazer a mesma coisa:
- Dependências implícitas – use os nomes dos parâmetros da função para indicar as dependências. Este método não funciona para código minimizado e deve, portanto, ser evitado.
- $inject – configura a propriedade $inject em um objeto que requer dependências de um array de nomes de dependência.
- Anotação de array em linha – transmite a lista de dependências como um array para a função constructor (como factory() ou controller()).
Dos três métodos acima descritos, o número 3 parece ser o mais aceito. Então, vamos reescrever o nosso código acima usando esse método. Primeiro, vamos dar uma olhada no serviço:
// simple, but not possible
@inject(Store, Mixer, Oven)
function Baker() {...}
// noisy, but possible
angular.module('PastryShop').factory('Baker', ['Store', 'Mixer', 'Oven',
function(Store, Mixer, Oven) {...}
]);
Em seguida, vamos reescrever o teste:
// simple, but not possible
@inject(Store, Mixer, Oven)
describe('Baker Service tests', function () {
it('should bake vanilla cake', function () {...});
});
// noisy, but possible
describe('Baker Service tests', function () {
var Baker, Store, Mixer, Oven;
beforeEach(angular.mock.module('PastryShop'));
beforeEach(function () {
angular.mock.inject(function (_Baker_, _Store_, _Mixer_, _Oven_) {
Baker = _Baker_;
Store = _Store_;
Mixer = _Mixer_;
Oven = _Oven_;
});
});
it('should bake vanilla cake', function () {...});
});
Vamos entender o que está acontecendo aqui. O Angular fornece um módulo especial chamado ngMock, que expõe (entre outras coisas) dois métodos muito úteis:
- module() – usado para iniciar seu aplicativo antes de cada teste.
- inject() – usado para obter instâncias de vários serviços injetadas em seus testes. Por convenção, se você fizer um wrap no nome do serviço em underscores, o Angular vai retirar esses underscores antes de te dar o serviço certo.
Assim que obtivermos os serviços necessários do inject(), vamos simplesmente armazená-los no escopo do nosso bloco describe(), e eles se tornarão disponíveis para todos os nossos testes.
Uma nota sobre controllers
Existem algumas coisas a mais que temos que levar em consideração ao testar controllers. Em primeiro lugar, para realmente criar um controller para nossos testes, precisamos usar o serviço $controller. Em segundo lugar, uma vez que a maioria dos controllers precisam de um $scope para trabalhar, podemos obter um usando o método $rootScope do $new().
Aqui está o código:
describe('Baker Controller tests', function () {
var scope, BakerController, Baker;
beforeEach(angular.mock.module('PastryShop'));
beforeEach(function () {
angular.mock.inject(function ($rootScope, $controller, _Baker_) {
scope = $rootScope.$new();
Baker = _Baker_;
BakerController = $controller('BakerController', {
$scope: scope,
Baker: Baker
});
});
});
});
Mais uma vez, estamos usando o método inject() para obter as nossas dependências, que nesse caso incluem $rootScope e $controller. Nós criamos uma instância de um $scope e o injetamos, juntamente com uma instância Baker, no BakerController.
***
Artigo traduzido pela Redação iMasters com autorização do autor. Publicado originalmente em http://tatiyants.com/groking-angular-dependency-injection-and-testing/






