Skip to main content

Introdução aos testes de unidade do Apex

Objetivos de aprendizagem

Após concluir esta unidade, você estará apto a:

  • Descrever os principais benefícios dos testes de unidade do Apex.
  • Definir uma classe com métodos de teste.
  • Executar todos os métodos de teste de uma classe e inspecionar falhas.
  • Criar e executar um conjunto de classes de teste.
Nota

Nota

O desafio prático para esse emblema está traduzido para japonês, espanhol (América Latina) e português (Brasil). Para definir o idioma do seu Trailhead Playground, siga essas instruções. A tradução pode estar desatualizada. Se você não conseguir passar no desafio usando as instruções traduzidas, defina o idioma para inglês e a localidade para Estados Unidos. Em seguida, tente novamente.

Consulte o emblema Trailhead no seu idioma para saber como aproveitar a experiência traduzida do Trailhead.

Testes de unidade do Apex

A estrutura de testes do Apex permite que você escreva e execute testes para suas classes e acionadores do Apex no Lightning Platform. Os testes de unidade do Apex garantem alta qualidade para seu código do Apex e lhe permitem cumprir os requisitos para implantação do Apex.

O teste é o segredo do desenvolvimento bem-sucedido em longo prazo e um componente essencial do processo de desenvolvimento. Com a estrutura de testes do Apex é mais fácil testar seu código do Apex. O código do Apex só pode ser escrito em um ambiente sandbox ou em uma organização do desenvolvedor, não na produção. O código do Apex pode ser implantado em uma organização de produção a partir de um sandbox. Além disso, desenvolvedores de aplicativos podem distribuir o código do Apex aos clientes de suas organizações de desenvolvedores carregando os pacotes para a Lightning Platform AppExchange. Além de serem fundamentais para a garantia de qualidade, os testes de unidade do Apex também são requisitos para implantar e distribuir o Apex. 

Estes são os benefícios dos testes de unidade do Apex.

  • Garantir que suas classes do Apex e acionadores funcionem conforme previsto
  • Ter um conjunto de testes de regressão que pode ser executado novamente sempre que as classes e os acionadores forem atualizados, a fim de garantir que as futuras atualizações que você vier a fazer ao seu aplicativo não interrompam a funcionalidade existente
  • Cumprir os requisitos de cobertura de código para a implantação do Apex na produção ou distribuição do Apex a clientes por meio de pacotes
  • Aplicativos de alta qualidade entregues à organização de produção, o que torna os usuários de produção mais produtivos
  • Aplicativos de alta qualidade entregues aos assinantes de pacotes, o que aumenta a confiança de seus clientes
Nota

Antes de cada atualização de serviço importante, o Salesforce executa todos os testes do Apex em seu nome usando um processo chamado Apex Hammer. O processo Hammer é executado na versão atual e no próximo lançamento, e compara os resultados dos testes. Esse processo faz com que o comportamento no seu código personalizado não seja alterado em função das atualizações de serviço. O processo Hammer seleciona as organizações com cuidado e não executa todas elas. Os problemas encontrados são selecionados com base em determinados critérios. O Salesforce se esforça para resolver todos os problemas encontrados antes de cada novo lançamento.

Manter seus dados seguros é a nossa maior prioridade. Não vemos ou modificamos os dados da sua organização; todos os testes são realizados em uma cópia que é executada em um data center seguro.

Requisito de cobertura de código para implantação

Antes de implantar seu código ou empacotá-lo para a Lightning Platform AppExchange, pelo menos 75% do código do Apex deve ser coberto por testes, e todos esses testes devem ser bem sucedidos. Além disso, cada acionador deve ter uma cobertura. Embora a cobertura de código seja um requisito para a implantação, não escreva testes apenas para atender a essa exigência. Teste os casos de uso comuns em seu aplicativo, incluindo casos positivos e negativos do teste, bem como o processamento em massa ou de um só registro.

Sintaxe do método de teste

Os métodos de teste são definidos usando a anotação @isTest e têm a seguinte sintaxe:

@isTest static void testName() {

  // code_block

}

A anotação @isTest utiliza vários modificadores entre parênteses e separados por espaços em branco. Abordaremos esse tipo de parâmetro mais tarde.

A visibilidade de um método de teste não importa, por isso, declarar um método de teste como público ou privado não faz diferença, pois a estrutura de testes é sempre capaz de acessar métodos de teste. Por essa razão, os modificadores de acesso são omitidos na sintaxe.

Os métodos de teste devem ser definidos em classes de teste, que são classes anotadas com @isTest. Esta classe de exemplo mostra uma definição de uma classe de teste com um método de teste.

@isTest

private class MyTestClass {

  @isTest static void myTest() {

    // code_block

  }

}

As classes de teste podem ser públicas ou privadas. Se você estiver usando uma classe de teste apenas para testes de unidade, declare-a como privada. As classes de teste públicas normalmente são utilizadas para classes de fábrica de dados de teste, sobre as quais falaremos mais tarde.

Exemplo de teste de unidade: Testar a classe TemperatureConverter

O exemplo simples a seguir pertence a uma classe de teste com três métodos de teste. O método de classe que está sendo testado possui uma temperatura em Fahrenheit como entrada. Ele converte essa temperatura para Celsius e informa o resultado convertido. Vamos adicionar a classe personalizada e sua classe de teste.

  1. No Developer Console, clique em File (Arquivo) | New (Novo) | Apex Class (Classe do Apex), digite TemperatureConverter como nome da classe e, em seguida, clique em OK.
  2. Substitua o corpo de classe padrão pelo seguinte.
    public class TemperatureConverter {
      // Takes a Fahrenheit temperature and returns the Celsius equivalent.
      public static Decimal FahrenheitToCelsius(Decimal fh) {
        Decimal cs = (fh - 32) * 5/9;
        return cs.setScale(2);
      }
    }
  3. Pressione Ctrl+S para salvar sua classe.
  4. Repita as etapas anteriores para criar a classe TemperatureConverterTest. Adicione o seguinte para esta classe.
    @isTest
    private class TemperatureConverterTest {
      @isTest static void testWarmTemp() {
        Decimal celsius = TemperatureConverter.FahrenheitToCelsius(70);
        System.assertEquals(21.11,celsius);
      }
      @isTest static void testFreezingPoint() {
        Decimal celsius = TemperatureConverter.FahrenheitToCelsius(32);
        System.assertEquals(0,celsius);
      }
      @isTest static void testBoilingPoint() {
        Decimal celsius = TemperatureConverter.FahrenheitToCelsius(212);
        System.assertEquals(100,celsius,'Boiling point temperature is not expected.');
      }
      @isTest static void testNegativeTemp() {
        Decimal celsius = TemperatureConverter.FahrenheitToCelsius(-10);
        System.assertEquals(-23.33,celsius);
      }
    }

A classe de teste TemperatureConverterTest verifica se o método funciona conforme previsto, chamando-o com diferentes entradas para a temperatura em Fahrenheit. Cada método de teste verifica um tipo de entrada: uma temperatura quente, a temperatura do ponto de congelamento, a temperatura do ponto de ebulição e uma temperatura negativa. As verificações são realizadas chamando-se o método System.assertEquals(), que utiliza dois parâmetros: o primeiro é o valor previsto, e o segundo é o valor real. Há uma outra versão desse método que utiliza um terceiro parâmetro – uma string que descreve a comparação que está sendo executada, que é utilizada em testBoilingPoint(). Essa string opcional é registrada caso a declaração falhe.

Vamos executar os métodos dessa classe.

  1. No Developer Console, clique em Test (Teste) | New Run (Nova execução).
  2. Em Test Classes (Classes de teste), clique em TemperatureConverterTest.
  3. Para adicionar todos os métodos de teste na classe TemperatureConverterTest para a execução de teste, clique em Add Selected (Adicionar selecionado).
  4. Clique em Run (Executar).
  5. Na guia Tests (Testes), você verá o status de seus testes durante o processo de execução. Expanda a execução de teste e expanda novamente até que possa ver a lista de testes individuais que foram executados. Todos eles têm marcas de seleção em verde. 
    Inspecionar os resultados dos testes no Developer Console

Depois de executar os testes, a cobertura de código é gerada automaticamente para as classes e acionadores do Apex presentes na organização. Você pode verificar a percentagem de cobertura de código na guia Tests (Testes) do Developer Console. Neste exemplo, a classe TemperatureConverter que você testou tem uma cobertura de 100%, conforme mostrado nesta imagem.

Visualizar a percentagem de cobertura de código no Developer Console

Nota

Sempre que modificar o código do Apex, execute novamente os testes para atualizar os resultados de cobertura de código.

Um problema conhecido com o Developer Console o impede de atualizar a cobertura de código corretamente ao executar um subconjunto de testes. Para atualizar seus resultados de cobertura de código, utilize Test (Teste) | Run All (Executar todos) em vez de Test (Teste) | New Run (Nova execução).

Embora um método de teste teria resultado em uma cobertura total da classe TemperatureConverter, ainda é importante testar diferentes entradas para garantir a qualidade do seu código. Obviamente, não é possível verificar todos os pontos de dados, mas você pode realizar testes em pontos de dados comuns e diferentes intervalos de entrada. Por exemplo, você pode verificar a aprovação de números positivos e negativos, valores-limite e valores de parâmetros inválidos para verificar o comportamento negativo. Os testes para a classe TemperatureConverter verificam os pontos de dados comuns, como a temperatura de ebulição e temperaturas negativas.

A classe de teste TemperatureConverterTest não abrange entradas inválidas ou condições-limite. As condições-limite se referem aos valores mínimos e máximos. Nesse caso, o método de conversão da temperatura aceita um Decimal, que pode aceitar números grandes, superiores a valores Double (Duplos). Para entradas inválidas, não há temperatura inválida, mas a única entrada inválida é null. Como o método de conversão lida com esse valor? Nesse caso, quando o tempo de execução do Apex desreferencia a variável do parâmetro para avaliar a fórmula, ele lança um System.NullPointerException. Você pode modificar o método FahrenheitToCelsius() para verificar se há uma entrada inválida e, nesse caso, retornar null e, em seguida, adicionar um teste para verificar o comportamento da entrada inválida.

Até este ponto, todos os testes são aprovados porque a fórmula de conversão utilizada no método de classe é correta. Mas isso é aborrecido! Tentaremos simular uma falha apenas para ver o que acontece quando uma declaração falha. Por exemplo, vamos modificar o teste de temperatura de ponto de ebulição e aprovar um valor falso previsto para a temperatura de ponto de ebulição em graus Celsius (0 em vez de 100). Isso faz com que o método de teste correspondente falhe.

  1. Altere o método de teste testBoilingPoint() para o seguinte.
    @isTest
    static void testBoilingPoint() {
      Decimal celsius = TemperatureConverter.FahrenheitToCelsius(212);
      // Simulate failure
      System.assertEquals(0,celsius,'Boiling point temperature is not expected.');
    }
  2. Para executar o mesmo teste, clique na última execução na guia Tests (Testes) e clique em Test (Testar) | Rerun (Executar novamente). A afirmação em testBoilingPoint() falha e lança um erro fatal (um AssertException que não pode ser pego).
  3. Verifique os resultados na guia Tests (Testes), expandindo a última execução de teste. A execução de teste informa a falha de um em cada quatro testes. Para obter mais detalhes sobre a falha, clique duas vezes na execução de teste. Os resultados detalhados aparecem em uma guia separada, conforme mostrado nesta imagem. 
    [Alt text: No Developer Console, inspecione os resultados de um teste com falha]
  4. Para obter a mensagem de erro da falha do teste, clique duas vezes dentro da coluna Errors (Erros) para acessar o teste com falha. Você verá o seguinte: o texto descritivo próximo a Assertion Failed: (Falha na asserção:) é o texto que fornecemos na instrução System.assertEquals() .

    System.AssertException:Assertion Failed:Boiling point temperature is not expected.:Expected:0, Actual:100.00 (System.AssertException:Falha na asserção:A temperatura de ponto de ebulição não é esperada.:Esperada:0, Real:100.00)

Os dados de teste nesses métodos de teste são números e não registros do Salesforce. Na próxima unidade, você aprenderá mais sobre como testar os registros do Salesforce e como configurar seus dados.

Aumente sua cobertura de código

Ao escrever testes, tente alcançar a maior cobertura de código possível. Não basta apontar para uma cobertura de 75%, que é a menor cobertura que a Lightning Platform exige para implantações e pacotes. Quanto mais casos de teste seus testes cobrirem, maior a probabilidade de o seu código ser robusto. Às vezes, mesmo depois de escrever métodos de teste para todos os seus métodos de classe, a cobertura de código não chega a 100%. Uma causa comum é não cobrir todos os valores de dados referentes à execução de código condicional. Por exemplo, alguns valores de dados tendem a ser ignorados quando seu método de classe possui instruções if que fazem com que diferentes ramificações sejam executadas desde que a condição avaliada seja atendida. Garanta que seus métodos de teste tenham em consideração esses valores diferentes.

Esse exemplo inclui o método de classe getTaskPriority(), que contém duas instruções if. A principal tarefa deste método é retornar um valor de string prioritário com base no estado de lead informado. O método valida primeiramente o estado e retorna null se ele for inválido. Se o estado for CA, o método retorna 'High'; caso contrário, retorna 'Normal' para qualquer outro valor de estado.

public class TaskUtil {

  public static String getTaskPriority(String leadState) {

    // Validate input

    if(String.isBlank(leadState) || leadState.length() > 2) {

      return null;

    }

    String taskPriority;

    if(leadState == 'CA') {

      taskPriority = 'High'; 

    } else {

      taskPriority = 'Normal';

    }

    return taskPriority;

  }

}
Nota

O operador de igualdade (==) realiza comparações de strings sem diferenciar caracteres maiúsculos e minúsculos, por isso não há necessidade de primeiramente converter a string para caracteres minúsculos. Isso significa que passar em 'ca' ou 'Ca' atenderá à condição de igualdade com a string literal 'CA'.

Esta é a classe de teste para o método getTaskPriority(). O método de teste simplesmente chama getTaskPriority() com um estado ('NY').

@isTest

private class TaskUtilTest {

  @isTest
  static void testTaskPriority() {

    String pri = TaskUtil.getTaskPriority('NY');

    System.assertEquals('Normal', pri);

  }

}

Vamos executar esta classe de teste (TaskUtilTest) no Developer Console e verificar a cobertura de código para a classe TaskUtil correspondente que este teste cobre. Após o término da execução do teste, a cobertura de código para TaskUtil é mostrada como 75%. Se abrir esta classe no Developer Console, verá seis linhas azuis (cobertas) e duas linhas vermelhas (descobertas), conforme mostrado nesta imagem.

Linhas cobertas para a classe TaskUtil no Developer Console

A linha 5 não foi coberta porque a nossa classe de teste não continha um teste para aprovar um parâmetro de estado inválido. Da mesma forma, a linha 11 não foi coberta porque o método de teste não aprovou 'CA' como estado. Vamos adicionar mais dois métodos de teste para cobrir esses cenários. A seguir, apresentamos a classe de teste completa após adicionarmos os métodos de teste testTaskHighPriority() e testTaskPriorityInvalid(). Se executar novamente essa classe de teste usando Run All (Executar todos) ou New Run (Nova execução), a cobertura de código para TaskUtil agora será de 100%!

@isTest

private class TaskUtilTest {

  @isTest

  static void testTaskPriority() {

    String pri = TaskUtil.getTaskPriority('NY');

    System.assertEquals('Normal', pri);

  }

  @isTest

  static void testTaskHighPriority() {

    String pri = TaskUtil.getTaskPriority('CA');

    System.assertEquals('High', pri);

  }

  @isTest

  static void testTaskPriorityInvalid() {

    String pri = TaskUtil.getTaskPriority('Montana');

    System.assertEquals(null, pri);

  }

}

Criar e executar um conjunto de testes

Um conjunto de testes é um conjunto de classes de teste do Apex que você executa juntas. Por exemplo, crie um conjunto de testes para ser executado sempre que você preparar uma implantação ou que a Salesforce liberar uma nova versão. Configure um conjunto de testes no Developer Console para definir um conjunto de classes de teste que são executadas juntas regularmente.

Agora você tem duas classes de teste em sua organização. Essas duas classes não estão relacionadas, mas por ora vamos fingir que estão. Suponhamos que haja situações em que você deseja executar essas duas classes de teste, mas não deseja executar todos os testes em sua organização. Crie um conjunto de testes que contenha ambas as classes e, em seguida, execute os testes no conjunto.

  1. No Developer Console, selecione Test (Teste) | New Suite (Novo conjunto).
  2. Insira TempConverterTaskUtilSuite como nome do conjunto e, em seguida, clique em OK.
  3. Selecione TaskUtilTest, mantenha a tecla Ctrl pressionada e, em seguida, selecione TemperatureConverterTest.
  4. Para adicionar as classes de teste selecionadas para o conjunto, clique em >Janela de edição do conjunto de testes com duas classes de teste selecionadas
  5. Clique em Salvar.
  6. Selecione Test (Teste) | New Suite Run (Execução de novo conjunto).
  7. Selecione TempConverterTaskUtilSuite e, em seguida, clique em > para mover TempConverterTaskUtilSuite até a coluna Selected Test Suites (Conjuntos de testes selecionados).
  8. Clique em Run Suites (Executar conjuntos).
  9. Na guia Tests (Testes), monitore o status de seus testes durante o processo de execução. Expanda a execução de teste e expanda novamente até que possa ver a lista de testes individuais que foram executados. Como em uma execução de métodos de teste individuais, você pode clicar duas vezes nos nomes dos métodos para ver os resultados dos testes detalhados.

Criar dados de teste

Os registros do Salesforce criados em métodos de teste não estão comprometidos com o banco de dados. Eles são revertidos quando a execução do teste é concluída. Esse comportamento de reversão é útil para testes porque você não tem que limpar seus dados de teste após o teste ser executado.

Por padrão, os testes do Apex não têm acesso aos dados preexistentes na organização, exceto para acesso a objetos de configuração e metadados, tais como os objetos Usuário ou Perfil. Configure os dados de teste dos seus testes. A criação de dados de teste deixa seus testes mais robustos e evita falhas causadas pela falta de dados ou por dados alterados na organização. Você pode criar dados de teste diretamente em seu método de teste ou utilizando uma classe de utilitário de teste, como veremos mais tarde.

Nota

Mesmo esta não sendo uma prática recomendada, há momentos em que um método de teste precisa de acesso a dados preexistentes. Para acessar os dados da organização, anote o método de teste com @isTest(SeeAllData=true). Os exemplos de métodos de teste desta unidade não acessam dados da organização e, portanto, não utilizam o parâmetro SeeAllData.

Quero saber mais

  • Você pode usar a Extensão Apex do Salesforce para o Visual Studio Code para executar testes do Apex e verificar a funcionalidade do seu código.
  • Você pode salvar até 6 MB de código do Apex em cada organização. As classes de teste anotadas com @isTest não contam para esse limite.
  • Embora os dados de teste sejam revertidos, nenhum banco de dados à parte é utilizado para testes. Como resultado, para alguns sObjects que têm campos com restrições exclusivas, a inserção de registros duplicados sObject resulta em um erro.
  • Os métodos de teste não enviam emails.
  • Os métodos de teste não podem fazer callouts para serviços externos. Você pode usar callouts simulados nos testes.
  • As pesquisas SOSL realizadas em um teste retornam resultados vazios. Para garantir resultados previsíveis, utilize Test.setFixedSearchResults() para definir os registros a serem retornados pela pesquisa.

Recursos

Preparar-se para o desafio prático

Para completar o desafio prático desta unidade, você precisará criar uma nova classe do Apex chamada VerifyDate com o código copiado abaixo:

public class VerifyDate {

  //method to handle potential checks against two dates

  public static Date CheckDates(Date date1, Date date2) {

    //if date2 is within the next 30 days of date1, use date2.  Otherwise use the end of the month

    if(DateWithin30Days(date1,date2)) {

      return date2;

    } else {

      return SetEndOfMonthDate(date1);

    }

  }

  //method to check if date2 is within the next 30 days of date1

  private static Boolean DateWithin30Days(Date date1, Date date2) {

    //check for date2 being in the past

    if( date2 < date1) { return false; }

    //check that date2 is within (>=) 30 days of date1

    Date date30Days = date1.addDays(30); //create a date 30 days away from date1

    if( date2 >= date30Days ) { return false; }

    else { return true; }

  }

  //method to return the end of the month of a given date

  private static Date SetEndOfMonthDate(Date date1) {

    Integer totalDays = Date.daysInMonth(date1.year(), date1.month());

    Date lastDay = Date.newInstance(date1.year(), date1.month(), totalDays);

    return lastDay;

  }

}
Continue a aprender de graça!
Inscreva-se em uma conta para continuar.
O que você ganha com isso?
  • Receba recomendações personalizadas para suas metas de carreira
  • Pratique suas habilidades com desafios práticos e testes
  • Monitore e compartilhe seu progresso com os empregadores
  • Conecte-se a orientação e oportunidades de carreira