Conceito
Para facilitar o
desenvolvimento e livrar o código de possíveis erros de lógica, o Salesforce exige a criação e execução de unit test
(teste de unidade) ou simplesmente de cobertura de código. Os testes de
unidade são compostos de métodos que verificam se uma determinada parte do
código está funcionando corretamente ou não e são declarados com a notação testMethod() ou utilizando a anotação isTest na definição do método. Além
disso o Salesforce possui uma classe especifica para criação de testes que é
chamada de “classe de teste”, que são as classes que recebem a anotação de isTest. Por exemplo:
@isTest
private class myClass {
static testMethod void myTest() {
code_block
}
}
Use o isTest para definir as
classes ou métodos individuais que apenas contêm o código usado para testar a
sua aplicação. A anotação isTest é semelhante a criação de métodos declarados
como testMethod, as classes que
possuem a anotação isTest não entram
no limite da organização de ter somente 3mb de código apex, pois são excluídas
desse limite.
Também podemos colocar 1 ou
mais métodos de teste dentro da mesma classe, veja o exemplo abaixo:
@isTest
private class MyTestClass {
@isTest static void test1() {
}
@isTest static void test2() {
}
}
Testando
chamadas de Webservices / HTTP Services
Quando queremos realizar uma
integração com o Salesforce entre outros aplicativos, geramos um wsdl do
serviço alvo e, a partir desse wsdl, geramos uma classe Apex contendo os métodos
que você pode chamar desse serviço Web. Para implantar o pacote desta classe
Apex e outros códigos de acompanhamento, é necessários que 75% do código seja testado, incluindo os
métodos na classe gerada. Por padrão, os métodos de teste não suportam chamadas
de serviço da Web e testes que realizam chamadas de serviço da Web são
ignorados. Para evitar que os testes sejam ignorados e para aumentar a
cobertura de código, o Apex fornece a interface de WebServiceMock e o método Test.setMock
que você pode usar para receber respostas falsas em um método de teste.
Antes de montar a nossa
classe de teste devemos criar a WebServiceMock,
veja o exemplo:
@isTest
global class WebServiceMockImpl implements WebServiceMock {
global void doInvoke(
Object stub,
Object request,
Map<String, Object> response,
String endpoint,
String soapAction,
String requestName,
String responseNS,
String responseName,
String responseType) {
docSample.EchoStringResponse_element respElement =
new docSample.EchoStringResponse_element();
respElement.EchoStringResult = 'Mock response';
response.put('response_x', respElement); }
}
Nossa classe está
implementando o WebServiceMock, que
nada mais é que uma interface do apex
code, a partir dessa interface criamos nossa chamada falsa de execução, o
método doInvoke, serve para disparar a
chamada para o método EchoString da
classe docSample, essa chamada é
possivel devido ao fato que estamos implementando o objeto de resposta que a
classe docSimple utiliza, esse objeto
é o EchoStringResponse_element().
Nossa classe de
teste iria invocar a classe WebServiceMockImpl da seguinte forma:
@isTest
private class WebSvcCalloutTest {
@isTest static void testEchoString() {
Test.setMock(WebServiceMock.class, new WebServiceMockImpl());
String output = WebSvcCallout.callEchoString('Hello World!');
System.assertEquals('Mock response', output);
}
}
A linha que define nossa
chamada falsa para teste é:
Test.setMock(WebServiceMock.class, new WebServiceMockImpl());
Nossa classe que deverá ser
testada é:
public class WebSvcCallout {
public static String callEchoString(String input) { docSample.DocSamplePort sample = new docSample.DocSamplePort();
String echo = sample.EchoString(input);
return echo;
}
}
Realizando esses passos
podemos testar chamadas para webservices, aonde o Salesforce não permiti realizar o
teste caso não criamos uma classe Mock.
Para as chamadas HTTP também
devemos implementar uma classe Mock,
que é uma interface chamada de HttpCalloutMock, a forma de chamada e implementação é
parecida com o visto acima, vejamos o código de exemplo:
@isTest
global class MockHttpResponseGenerator implements HttpCalloutMock {
global HTTPResponse respond(HTTPRequest req) {
System.assertEquals('http://api.salesforce.com/foo/bar', req.getEndpoint());
System.assertEquals('GET', req.getMethod());
HttpResponse res = new HttpResponse();
res.setHeader('Content-Type', 'application/json');
res.setBody('{"foo":"bar"}');
res.setStatusCode(200);
return res;
}
}
Deve ser definido todo o
cabeçalho HTTP de resposta da nossa chamada falsa, no nosso exemplo estamos
utilizando o método GET, caso fosse
um POST deve-se modificar as
seguintes linhas:
System.assertEquals('POST', req.getMethod());
res.setHeader('Content-Type', 'application/x-www-form-urlencoded');
Modificação simples para se
trabalhar com o método POST, agora
dentro da nossa classe de teste a chamada seria da seguinte forma utilizando o
método POST ou GET.
@isTest
private class CalloutClassTest {
@isTest static void testCallout() {
Test.setMock(HttpCalloutMock.class, new MockHttpResponseGenerator());
HttpResponse res = CalloutClass.getInfoFromExternalService();
String contentType = res.getHeader('Content-Type');
System.assert(contentType == 'application/json');
String actualValue = res.getBody();
String expectedValue = '{"foo":"bar"}';
System.assertEquals(actualValue, expectedValue);
System.assertEquals(200, res.getStatusCode());
}
}
Nossa classe que estamos testando é
a que segue:
public class CalloutClass {
public static HttpResponse getInfoFromExternalService() {
HttpRequest req = new HttpRequest();
req.setEndpoint('http://api.salesforce.com/foo/bar');
req.setMethod('GET');
Http h = new Http();
HttpResponse res = h.send(req);
return res;
}
}
Pulo
do gato
Nos testes dentro do
Salesforce com chamadas externas (HTTP, WebServices, API, etc) é bom sempre
utilizarmos a notação:
Test.startTest();
Para iniciar o teste é:
Test.stopTest();
Ao final da execução do
teste, ficando da seguinte forma:
@isTest
private class CalloutClassTest {
static void testCallout() {
Test.startTest();
Test.setMock(HttpCalloutMock.class, new MockHttpResponseGenerator());
HttpResponse res = CalloutClass.getInfoFromExternalService();
String contentType = res.getHeader('Content-Type');
System.assert(contentType == 'application/json');
String actualValue = res.getBody();
String expectedValue = '{"foo":"bar"}';
System.assertEquals(actualValue, expectedValue);
System.assertEquals(200, res.getStatusCode());
Test.stopTest();}
}
O principal objetivo desses
métodos é ter certeza de que todos os trabalhos assíncronos expostos pelo teste
(@Future, batch apex, scheduled apex) serão executados como parte do teste.
Outro pulo do gato é a
questão de teste em classes que possuem SOQL, o Salesforce não permite que as
classes de teste acessem a base de dados, para contornar esse problema devemos
utilizar a seguinte notação na declaração da classe de teste:
@isTest(SeeAllData=true)
private class CalloutClassTest {
Essa notação permite o
acesso a SOQL pelas classes de testes assim podendo ser testadas as classes que
possuem SOQL.
Escrito por: Rafael Soares Souza
- Bacharel em Sistemas de
Informação – UMC, Analista de Sistemas. NET/C# há mais de 4 anos,
desenvolvedor Salesforce na MakeITSimple. DATA CENTER TECHNICAL SPECIALIST (DCTS), CERTIFIED LINUX ADMINISTRATOR (CLA11), LPIC-1.
- Perfil no LinkedIn: http://br.linkedin.com/pub/rafael-soares-souza/43/609/107