Estou construindo uma biblioteca de classes que terá alguns métodos públicos e privados. Eu quero poder testar os métodos privados (principalmente durante o desenvolvimento, mas também pode ser útil para refatoração futura).
Qual é a maneira correta de fazer isso?
.net
unit-testing
tdd
private
Eric Labashosky
fonte
fonte
pre-historic
em termos de anos na Internet, mas o teste de unidade de métodos privados agora é fácil e direto, com o Visual Studio produzindo as classes de acessador necessárias quando necessário e pré-preencher a lógica dos testes com trechos muito próximos do que se pode desejar para testes funcionais simples. Veja por exemplo. msdn.microsoft.com/pt-br/library/ms184807%28VS.90%29.aspxRespostas:
Se você estiver usando .net, use o InternalsVisibleToAttribute .
fonte
#if DEBUG
torno doInternalsVisibleTo
atributo para torná-lo não se aplica ao código de liberação?#if RELEASE_TEST
em torno deInternalsVisibleTo
como Mike sugere, e faça uma cópia de sua configuração de compilação de lançamento que defineRELEASE_TEST
. Você pode testar seu código de versão com otimizações, mas quando você realmente cria para a versão, seus testes serão omitidos.Se você quiser testar um método privado, algo pode estar errado. Os testes de unidade são (geralmente falando) destinados a testar a interface de uma classe, significando seus métodos públicos (e protegidos). É claro que você pode "hackear" uma solução para isso (mesmo que apenas tornando os métodos públicos), mas você também pode querer considerar:
fonte
Pode não ser útil testar métodos privados. No entanto, às vezes também gosto de chamar métodos privados a partir de métodos de teste. Na maioria das vezes, para evitar a duplicação de código para geração de dados de teste ...
A Microsoft fornece dois mecanismos para isso:
Accessors
No entanto, o mecanismo às vezes é um pouco intratável quando se trata de alterações na interface da classe original. Então, na maioria das vezes eu evito usar isso.
Classe PrivateObject A outra maneira é usar Microsoft.VisualStudio.TestTools.UnitTesting.PrivateObject
fonte
Não concordo com a filosofia "você só deveria estar interessado em testar a interface externa". É um pouco como dizer que uma oficina de automóveis só deve ter testes para ver se as rodas giram. Sim, em última análise, estou interessado no comportamento externo, mas eu gosto que meus próprios testes internos sejam um pouco mais específicos e diretos. Sim, se eu refatorar, talvez eu precise alterar alguns dos testes, mas, a menos que seja um refatorio massivo, só precisarei alterar alguns e o fato de os outros testes internos (inalterados) ainda funcionarem é um ótimo indicador de que a refatoração foi bem sucedida.
Você pode tentar cobrir todos os casos internos usando apenas a interface pública e, teoricamente, é possível testar todos os métodos internos (ou pelo menos todos os que importam) inteiramente usando a interface pública, mas você pode ter que ficar de cabeça para alcançar isso e a conexão entre os casos de teste que estão sendo executados pela interface pública e a parte interna da solução projetada para teste podem ser difíceis ou impossíveis de discernir. Tendo apontado, testes individuais que garantem que o maquinário interno esteja funcionando corretamente valem bem as pequenas alterações de teste que ocorrem com a refatoração - pelo menos essa tem sido minha experiência. Se você precisar fazer grandes alterações em seus testes para cada refatoração, talvez isso não faça sentido, mas nesse caso, talvez você deva repensar completamente seu design.
fonte
FooService
que precisa fazerX
, tudo o que você deve se preocupar é que ele realmente fazX
quando solicitado. Como isso acontece, não deve importar. Se houver problemas na classe que não sejam discerníveis através da interface (improvável), ainda será válidoFooService
. Se é um problema que é visível através da interface, um teste em membros públicos deve detectá-lo. O ponto principal deve ser que, desde que a roda gire corretamente, ela possa ser usada como uma roda.PrivMethod
, um teste noPubMethod
qual as chamadasPrivMethod
devem expô-lo? O que acontece quando você mudaSimpleSmtpService
para aGmailService
? De repente, seus testes particulares apontam para um código que não existe mais ou que talvez funcione de maneira diferente e que falharia, mesmo que o aplicativo funcione perfeitamente como projetado. Se houver um processamento complexo que se aplicaria a ambos os remetentes de e-mail, talvez ele deva estar em umEmailProcessor
que possa ser usado por ambos e testado separadamente?Nos raros casos em que eu queria testar funções privadas, geralmente as modifiquei para serem protegidas e escrevi uma subclasse com uma função de invólucro público.
A classe:
Subclasse para teste:
fonte
Eu acho que uma pergunta mais fundamental deve ser feita: por que você está tentando testar o método privado em primeiro lugar? É um cheiro de código que você está tentando testar o método privado através da interface pública dessa classe, enquanto esse método é privado por um motivo, pois é um detalhe de implementação. Deve-se preocupar apenas com o comportamento da interface pública e não com a maneira como ela é implementada nos bastidores.
Se eu quiser testar o comportamento do método privado, usando refatorações comuns, posso extrair seu código para outra classe (talvez com visibilidade no nível do pacote, para garantir que não faça parte de uma API pública). Posso então testar seu comportamento isoladamente.
O produto da refatoração significa que o método privado agora é uma classe separada que se tornou um colaborador da classe original. Seu comportamento será bem compreendido por meio de seus próprios testes de unidade.
Posso então zombar de seu comportamento quando tento testar a classe original, para poder me concentrar em testar o comportamento da interface pública dessa classe, em vez de ter que testar uma explosão combinatória da interface pública e o comportamento de todos os seus métodos privados .
Eu vejo isso como dirigir um carro. Quando dirijo um carro, não dirijo com o capô para cima, para ver que o motor está funcionando. Eu confio na interface que o carro fornece, ou seja, o conta-rotações e o velocímetro para saber que o motor está funcionando. Eu confio no fato de que o carro realmente se move quando eu pressiono o acelerador. Se eu quiser testar o mecanismo, posso verificar isso isoladamente. : D
É claro que testar métodos privados diretamente pode ser o último recurso se você tiver um aplicativo herdado, mas eu preferiria que o código herdado seja refatorado para permitir um teste melhor. Michael Feathers escreveu um ótimo livro sobre esse assunto. http://www.amazon.co.uk/Working-Effectively-Legacy-Robert-Martin/dp/0131177052
fonte
Tipos particulares, internos e membros particulares são assim por algum motivo, e muitas vezes você não deseja mexer com eles diretamente. E, se o fizer, é provável que você quebre mais tarde, porque não há garantia de que os caras que criaram esses assemblies manterão as implementações privadas / internas como tal.
Mas, às vezes, ao fazer alguns hacks / exploração de montagens compiladas ou de terceiros, acabei desejando inicializar uma classe privada ou uma classe com um construtor privado ou interno. Ou, às vezes, ao lidar com bibliotecas legadas pré-compiladas que não posso alterar - acabo escrevendo alguns testes em um método privado.
Assim nasceu o AccessPrivateWrapper - http://amazedsaint.blogspot.com/2010/05/accessprivatewrapper-c-40-dynamic.html - é uma classe de wrapper rápida que facilita o trabalho usando os recursos dinâmicos e a reflexão do C # 4.0.
Você pode criar tipos internos / privados como
fonte
Bem, você pode testar o método privado de duas maneiras
você pode criar instância da
PrivateObject
classe, a sintaxe é a seguinteVocê pode usar reflexão.
fonte
PrivateClass
primeiro e usá-la. stackoverflow.com/questions/9122708/…Eu também usei o método InternalsVisibleToAttribute. Vale ressaltar também que, se você se sentir desconfortável ao tornar seus métodos anteriormente privados internos para conseguir isso, talvez eles não devam ser submetidos a testes de unidade diretos.
Afinal, você está testando o comportamento de sua classe, em vez de sua implementação específica - você pode alterar o último sem alterar o anterior e seus testes ainda devem passar.
fonte
Existem 2 tipos de métodos privados. Métodos privados estáticos e métodos privados não estáticos (métodos de instância). Os 2 artigos a seguir explicam como testar métodos particulares com exemplos.
fonte
O MS Test possui um bom recurso interno que disponibiliza membros e métodos privados no projeto, criando um arquivo chamado VSCodeGenAccessors
Com classes derivadas de BaseAccessor
tal como
fonte
No CodeProject, há um artigo que discute brevemente os prós e contras do teste de métodos particulares. Em seguida, fornece algum código de reflexão para acessar métodos privados (semelhante ao código que Marcus fornece acima.) O único problema que encontrei com a amostra é que o código não leva em consideração os métodos sobrecarregados.
Você pode encontrar o artigo aqui:
http://www.codeproject.com/KB/cs/testnonpublicmembers.aspx
fonte
Declare-os
internal
e use oInternalsVisibleToAttribute
para permitir que seu conjunto de teste da unidade os veja.fonte
Eu costumo não usar diretivas do compilador porque elas bagunçam as coisas rapidamente. Uma maneira de atenuá-lo se você realmente precisar deles é colocá-los em uma classe parcial e fazer com que sua construção ignore esse arquivo .cs ao criar a versão de produção.
fonte
Você não deve testar os métodos particulares do seu código em primeiro lugar. Você deve testar a 'interface pública' ou API, o conteúdo público de suas classes. A API são todos os métodos públicos que você expõe a chamadores externos.
O motivo é que, assim que você começa a testar os métodos privados e internos da sua classe, está acoplando a implementação da sua classe (as coisas particulares) aos seus testes. Isso significa que, quando você decide alterar os detalhes de sua implementação, também precisará alterar seus testes.
Por esse motivo, evite usar InternalsVisibleToAtrribute.
Aqui está uma ótima conversa de Ian Cooper, que aborda este assunto: Ian Cooper: TDD, onde tudo deu errado
fonte
Às vezes, pode ser bom testar declarações privadas. Fundamentalmente, um compilador possui apenas um método público: Compile (string outputFileName, params string [] sourceSFileNames). Tenho certeza que você entende que seria difícil testar esse método sem testar cada declaração "oculta"!
Por isso, criamos o Visual T #: para facilitar os testes. É uma linguagem de programação .NET gratuita (compatível com C # v2.0).
Nós adicionamos o operador '.-'. Apenas se comporta como '.' operador, exceto que você também pode acessar qualquer declaração oculta de seus testes sem alterar nada em seu projeto testado.
Dê uma olhada no nosso site: baixar -lo gratuitamente .
fonte
Estou surpreso que ninguém tenha dito isso ainda, mas uma solução que empreguei é criar um método estático dentro da classe para testar a si mesmo. Isso lhe dá acesso a tudo o que é público e privado para testar.
Além disso, em uma linguagem de script (com recursos de OO, como Python, Ruby e PHP), você pode fazer o teste do arquivo quando executar. Ótima maneira rápida de garantir que suas alterações não quebrem nada. Obviamente, isso cria uma solução escalável para testar todas as suas classes: basta executá-las. (você também pode fazer isso em outros idiomas com um void main que sempre executa seus testes também).
fonte
Quero criar um exemplo de código claro aqui, que você pode usar em qualquer classe na qual deseja testar o método privado.
Na sua classe de caso de teste, inclua esses métodos e depois os empregue conforme indicado.
$ this -> _ callMethod ('_ someFunctionName', array (param1, param2, param3));
Basta emitir os parâmetros na ordem em que aparecem na função privada original
fonte
Para quem quer executar métodos privados sem todo o estresse e confusão. Isso funciona com qualquer estrutura de teste de unidade usando nada além do bom e velho Reflection.
Em seus testes reais, você pode fazer algo assim:
fonte
O MbUnit conseguiu um bom invólucro para este chamado Refletor.
Você também pode definir e obter valores das propriedades
Em relação ao "teste privado", eu concordo que .. no mundo perfeito. não faz sentido fazer testes de unidade privada. Mas no mundo real, você pode querer escrever testes particulares em vez de refatorar o código.
fonte
Reflector
foi substituído pelo mais poderosoMirror
do Gallio / MbUnit v3.2. ( gallio.org/wiki/doku.php?id=mbunit:mirror )Aqui está um bom artigo sobre teste de unidade de métodos privados. Mas não tenho certeza do que é melhor: tornar seu aplicativo projetado especialmente para testes (é como criar testes apenas para testes) ou usar a reflexão para testes. Certamente a maioria de nós escolherá o segundo caminho.
fonte
Na minha opinião, você deve testar apenas a API pública da sua classe.
Tornar um método público, para testá-lo por unidade, quebra o encapsulamento, expondo os detalhes da implementação.
Uma boa API pública resolve um objetivo imediato do código do cliente e resolve esse objetivo completamente.
fonte
Eu uso a classe PrivateObject . Mas, como mencionado anteriormente, é melhor evitar testar métodos privados.
fonte
"CC" é o compilador de linha de comando no sistema que eu uso.
-Dfoo=bar
faz o equivalente a#define foo bar
. Portanto, essa opção de compilação efetivamente altera todas as coisas privadas para públicas.fonte
Aqui está um exemplo, primeiro a assinatura do método:
Aqui está o teste:
fonte
Uma maneira de fazer isso é ter seu método
protected
e escrever um acessório de teste que herda sua classe a ser testada. Dessa forma, você não está mudando seu métodopublic
, mas habilita o teste.fonte
1) Se você possui um código legado, a única maneira de testar métodos privados é por reflexão.
2) Se for um novo código, você terá as seguintes opções:
Prefiro o método de anotação, mais simples e menos complicado. A única questão é que aumentamos a visibilidade, o que eu acho que não é uma grande preocupação. Devemos sempre codificar a interface, portanto, se tivermos uma interface MyService e uma implementação MyServiceImpl, poderemos ter as classes de teste correspondentes que são MyServiceTest (métodos de interface de teste) e MyServiceImplTest (métodos privados de teste). Todos os clientes devem, de qualquer maneira, estar usando a interface, de modo que, mesmo que a visibilidade do método privado tenha aumentado, isso realmente não deve importar.
fonte
Você também pode declarar como público ou interno (com InternalsVisibleToAttribute) ao criar no modo de depuração:
Ele incha o código, mas estará
private
em uma versão compilada.fonte
Você pode gerar o método de teste para o método privado no Visual studio 2008. Quando você cria um teste de unidade para um método privado, uma pasta Referências de Teste é adicionada ao seu projeto de teste e um acessador é adicionado a essa pasta. O acessador também é referido na lógica do método de teste de unidade. Esse acessador permite que seu teste de unidade chame métodos particulares no código que você está testando. Para mais detalhes, consulte
http://msdn.microsoft.com/en-us/library/bb385974.aspx
fonte
Observe também que o InternalsVisibleToAtrribute tem um requisito de que seu assembly tenha um nome forte , o que cria seu próprio conjunto de problemas se você estiver trabalhando em uma solução que não tinha esse requisito antes. Eu uso o acessador para testar métodos privados. Veja esta pergunta que, para um exemplo disso.
fonte
InternalsVisibleToAttribute
que não exigem que suas montagens ser fortemente nomeado. Atualmente, eu o uso em um projeto em que esse não é o caso.