Antes de fazer qualquer teste de unidade sério em JS, eu fiz muito em PHP. Quando queria verificar se algo é uma instância de outra coisa, simplesmente fiz algo como:
$this->assertTrue($foo instanceof Bar);
Isso também é possível em JS. No entanto, você precisa de acesso ao construtor para fazer isso.
function foo(x) {
function Foo(x) {
// something
}
return new Foo(x);
}
y = foo(1);
// can't do "y instanceof Foo" because Foo is not in the current scope
Agora imagine que você tem este serviço de repositório em seu aplicativo angular e deseja verificar se ‘getCurrent’ responde com uma promessa:
(function (angular) {
var app = angular.module('app');
var UserRepository = function ($http, CONFIG) {
var baseUrl = CONFIG.api.baseUrl;
this.getCurrent = function () {
return $http.get(baseUrl + '/me');
};
// more code here
};
app.service('UserRepository', ['$http', 'CONFIG', UserRepository]);
}(window.angular));
Protótipos para o resgate:
// we have $q service already injected
output = UserRepository.getCurrent(); expect(output.__proto__).toBe($q.defer().promise.__proto__);
Post Scriptum
Lembre-se de que JS é uma linguagem digitada dinamicamente e mesmo que seu objeto seja baseado em algum protótipo, isso não significa que os métodos exigidos por você não serão desvinculados no caminho. A maioria dos desenvolvedores não fará coisas assim, mas ainda é possível. Vamos ficar um pouco paranóicos por um tempo. Então…
Outra maneira de testar seu objeto seria verificar se ele possui os métodos de que você precisa:
expect(typeof output.then).toBe('function');
expect(typeof output.success).toBe('function');
expect(typeof output.error).toBe('function');
É a chamada digitação de pato – se grasna e voa – é um pato. Se ele tiver o mesmo conjunto de métodos que um objeto de promessa de que precisamos – isso significa que é nosso objeto de promessa.
Mesmo assim, isso não significa que essas funções corresponderão à interface de que você precisa (os argumentos de entrada e o valor de retorno podem ser diferentes do que você precisa).
Se você deseja ter 100% de certeza de que nosso ‘getCurrent’ retorna exatamente a mesma coisa que $ http.get – você pode, por exemplo, simular o serviço $ http para esse teste de unidade. Uma maneira de fazer isso seria:
describe('UserRepository.getCurrent', function () {
var httpMock;
var UserRepository;
var getReturnValue = {}; // just a plain object to be used to verify if both $http.get and UserRepository.getCurrent will return that exact object
beforeEach(function () {
module('app', function ($provide) {
// create a mock
httpMock = jasmine.createSpyObj('$http', ['get']);
httpMock.get.and.callFake(function () {
return getReturnValue;
});
// replace $http definition with our mock
$provide.service('$http', function () {
return httpMock;
});
});
// inject service we're about to test - it will get our mocked $http
inject(function (_UserRepository_) {
UserRepository = _UserRepository_;
});
});
// test
it('should return $http's promise', function () {
expect(UserRepository.getCurrent()).toBe(getReturnValue);
});
});
E é isso. Você conhece uma maneira melhor? Eu sou todo seu.