Sei que essa é uma prática debatida, mas vamos supor que essa seja a melhor opção para mim. Eu estou pensando sobre qual é a técnica real para fazer isso. A abordagem que vejo é a seguinte:
1) Faça a classe de um amigo a classe que é o método que eu quero testar.
2) Na classe friend, crie um método público que chame o método privado da classe testada.
3) Teste os métodos públicos da classe de amigos.
Aqui está um exemplo simples para ilustrar as etapas acima:
#include <iostream>
class MyClass
{
friend class MyFriend; // Step 1
private:
int plus_two(int a)
{
return a + 2;
}
};
class MyFriend
{
public:
MyFriend(MyClass *mc_ptr_1)
{
MyClass *mc_ptr = mc_ptr_1;
}
int plus_two(int a) // Step 2
{
return mc_ptr->plus_two(a);
}
private:
MyClass *mc_ptr;
};
int main()
{
MyClass mc;
MyFriend mf(&mc);
if (mf.plus_two(3) == 5) // Step 3
{
std::cout << "Passed" << std::endl;
}
else
{
std::cout << "Failed " << std::endl;
}
return 0;
}
Editar:
Vejo que, na discussão a seguir, uma das respostas que as pessoas estão se perguntando sobre minha base de código.
Minha classe possui métodos chamados por outros métodos; nenhum desses métodos deve ser chamado fora da classe, portanto deve ser privado. É claro que eles poderiam ser colocados em um método, mas logicamente eles são muito melhores separados. Esses métodos são complicados o suficiente para justificar o teste de unidade e, devido a problemas de desempenho, provavelmente terei que refazer esses métodos; portanto, seria bom fazer um teste para garantir que minha re-fatoração não quebrasse nada. Não sou o único que trabalha na equipe, embora seja o único que está trabalhando neste projeto, incluindo os testes.
Dito isso, minha pergunta não era sobre se é uma boa prática escrever testes de unidade para métodos privados, embora eu aprecie o feedback.
fonte
Respostas:
Uma alternativa ao amigo (bem, em certo sentido) que eu uso com frequência é um padrão que eu conheci como access_by. É bem simples:
Agora, suponha que a classe B esteja envolvida no teste A. Você pode escrever isto:
Você pode usar essa especialização de access_by para chamar métodos privados de A. Basicamente, o que isso faz é colocar o ônus de declarar amizade no arquivo de cabeçalho da classe que deseja chamar os métodos privados de A. Também permite adicionar amigos a A sem alterar a fonte de A. Linguisticamente, também indica para quem lê a fonte de A que A não indica B como um verdadeiro amigo no sentido de estender sua interface. Em vez disso, a interface de A é completa, conforme determinado, e B precisa de acesso especial a A (o teste é um bom exemplo, eu também usei esse padrão ao implementar ligações de python de aumento, às vezes uma função que precisa ser privada em C ++ é útil para expor na camada python para a implementação).
fonte
friend access_by
, não é o primeiro não amigo suficiente - sendo uma estrutura aninhada, ele teria acesso a tudo em A? por exemplo. coliru.stacked-crooked.com/a/663dd17ed2acd7a3Se é difícil de testar, está mal escrito
Se você tem uma classe com métodos privados complexos o suficiente para justificar seu próprio teste, a classe está fazendo muito. Dentro, há outra turma tentando sair.
Extraia os métodos particulares que você deseja testar em uma nova classe (ou classes) e torne-os públicos. Teste as novas classes.
Além de tornar o código mais fácil de testar, essa refatoração tornará o código mais fácil de entender e manter.
fonte
Você não deveria estar testando métodos privados. Período. As classes que usam sua classe se preocupam apenas com os métodos que ela fornece, não com os métodos usados para funcionar.
Se você está preocupado com a cobertura do código, precisa encontrar configurações que permitam testar esse método privado a partir de uma das chamadas de método públicas. Se você não pode fazer isso, qual é o sentido de ter o método em primeiro lugar? É simplesmente código inacessível.
fonte
Existem algumas opções para fazer isso, mas lembre-se de que elas (em essência) modificam a interface pública de seus módulos, para fornecer acesso a detalhes de implementação interna (transformando efetivamente o teste de unidade em dependências de cliente fortemente acopladas, onde você deve ter nenhuma dependência).
você pode adicionar uma declaração de amigo (classe ou função) à classe testada.
você pode adicionar
#define private public
ao início dos seus arquivos de teste antes de#include
inserir o código testado. No entanto, caso o código testado seja uma biblioteca já compilada, isso poderá fazer com que os cabeçalhos não correspondam mais ao código binário já compilado (e causem UB).você pode inserir uma macro na sua classe testada e decidir posteriormente o que essa macro significa (com uma definição diferente para testar o código). Isso permitiria testar internamente, mas também permitiria que o código do cliente de terceiros invadisse sua classe (criando sua própria definição na declaração que você adicionou).
fonte
Aqui está uma sugestão questionável para uma pergunta questionável. Eu não gosto do acoplamento de amigo, já que o código liberado precisa saber sobre o teste. A resposta de Nir é uma maneira de aliviar isso, mas ainda não gosto muito de mudar de classe para se adequar ao teste.
Como não confio na herança com frequência, às vezes apenas protejo os métodos privados, e tenho uma classe de teste que herda e expõe conforme necessário. A realidade é que a API pública e a API de teste podem diferir e ainda ser distintas da API privada, o que deixa você em uma espécie de ligação.
Aqui está um exemplo prático desse tipo para o qual recorro. Eu escrevo código incorporado e confiamos bastante em máquinas de estado. A API externa não precisa necessariamente saber sobre o estado interno da máquina de estado, mas o teste deve (sem dúvida) testar a conformidade com o diagrama da máquina de estado no documento de design. Eu posso expor um getter de "estado atual" como protegido e, em seguida, dar acesso ao teste, permitindo que eu teste a máquina de estado mais completamente. Costumo achar esse tipo de aula difícil de testar como uma caixa preta.
fonte
Você pode escrever seu código com várias soluções alternativas para impedir que você use amigos.
Você pode escrever classes e nunca ter nenhum método privado. Tudo o que você precisa fazer é criar funções de implementação na unidade de compilação, deixar sua classe chamá-las e passar os membros de dados que eles precisam acessar.
E sim, isso significa que você pode alterar as assinaturas ou adicionar novos métodos de "implementação" sem alterar o cabeçalho no futuro.
Você tem que ponderar se vale ou não a pena. E muito dependerá realmente de quem verá seu cabeçalho.
Se eu estiver usando uma biblioteca de terceiros, prefiro não ver declarações de amigos para seus testadores de unidade. Também não quero construir a biblioteca deles e executar os testes quando o fizer. Infelizmente, muitas bibliotecas de código aberto de terceiros que eu construí fazem isso.
Testar é o trabalho dos escritores da biblioteca, não de seus usuários.
No entanto, nem todas as classes são visíveis para o usuário da sua biblioteca. Muitas classes são "implementação" e você as implementa da melhor maneira para garantir que elas funcionem corretamente. Nesses, você ainda pode ter métodos e membros particulares, mas deseja que os testadores de unidade os testem. Portanto, vá em frente e faça dessa maneira, se isso levar a um código robusto mais rápido, fácil de manter para quem precisa fazer isso.
Se os usuários de sua classe estiverem todos dentro da sua própria empresa ou equipe, você também poderá relaxar um pouco mais sobre essa estratégia, supondo que ela seja permitida pelos padrões de codificação da sua empresa.
fonte