Início Facebook Twitter Vá para nosso Site Início Dicas Tutoriais Fale Conosco Image Map

Técnicas de Teste Salesforce

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