Este artigo compara quatro abordagens diferentes para testar métodos privados em classes Java.
meu primeiro uso de JUnit foi construir um kit de teste de conformidade para a API ServiceUI . O objetivo de um kit de teste de conformidade é ajudar a garantir que implementações alternativas da mesma API são compatíveis com a especificação da API. Uma vez que uma especificação API define apenas a interface pública da API, não a implementação da API, um teste de Conformidade exerce apenas a interface pública. Por outras palavras, um teste de conformidade é um teste de “caixa negra”. Ele trata a API sob teste como uma caixa preta, cuja interface externa pode ser vista, mas cuja implementação interna não pode. Um teste de Conformidade de uma API Java, portanto, só precisa acessar os membros públicos dos pacotes e classes em teste. Não há necessidade de acesso a pacotes-nível, protegidos, ou membros privados.Quando eu mais tarde apliquei JUnit para a tarefa de escrever testes de unidade reais, ao contrário de testes de Conformidade, eu me encontrei querendo escrever testes de caixa branca—testes que empregam conhecimento da implementação interna dos pacotes e classes sob teste. Enquanto eu só queria testar métodos públicos em meus testes de Conformidade, eu queria escrever testes de unidade para o acesso a pacotes e, ocasionalmente, métodos privados, bem como métodos públicos.
Daniel Steinberg me mostrou a técnica comum de JUnit de usar árvores de código fonte paralelas, o que me permitiu colocar classes de teste no mesmo pacote que as classes sob teste, mas mantê-las em um diretório diferente. Isto proporcionou uma separação limpa do código de ensaio e produção. Ao colocar ambas as árvores-fonte no CLASPATH, minhas classes de teste poderiam acessar métodos e classes de nível de pacote no pacote sob teste. Isso ainda me deixou, no entanto, com o problema de testar métodos privados.Quando perguntei ao Daniel sobre o teste de métodos privados, ele sugeriu gentilmente que eu testasse os métodos privados indiretamente testando os métodos de acesso a pacotes e os métodos públicos que chamam os privados. Esta resposta não me satisfez totalmente, porque, por vezes, senti realmente a necessidade de testar directamente um método privado. Minha solução inicial era apenas fazer esses métodos privados de acesso a pacotes, o que me permitiu testá-los diretamente com JUnit das classes de teste no mesmo pacote na árvore fonte paralela. Isto funcionou bem, mas fez-me sentir um pouco sujo de alguma forma. Embora em geral eu descobri que pensar sobre como projetar interfaces para que elas pudessem ser facilmente testadas por unidade me ajudou a projetar melhores interfaces, neste caso eu senti que eu estava fazendo o projeto um pouco pior para torná-lo testável.Quando eu mais tarde acabei participando da criação do que Frank Sommers, Matt Gerrans, e eu eventualmente liberado como Artima SuiteRunner , eu jurei que tornaria o teste de métodos privados mais fácil no SuiteRunner do que no JUnit. Mas depois de investigar as várias abordagens para testar métodos privados, eu decidi não fazer nada de especial no SuiteRunner para apoiar testes métodos privados. Por isso, quer esteja a usar o JUnit ou o SuiteRunner, tem as mesmas quatro abordagens básicas para testar métodos privados:
- não testem métodos privados.
- dar aos métodos acesso à embalagem.
- utilize uma classe de teste aninhada.
- utilize reflexão.
neste artigo, vou discutir estas quatro abordagens para testar métodos privados em Java. Analisarei as vantagens e desvantagens de cada uma e procurarei esclarecer quando é que faz sentido utilizar cada abordagem. Como mencionei na introdução, ouvi pela primeira vez o conselho para suprimir os meus impulsos ocasionais para testar métodos privados de Daniel Steinberg. Mas o Daniel não é apenas a fonte deste conselho que encontrei. Parece ser uma atitude comum na comunidade Java. Por exemplo, a FAQ JUnit afirma:
testar métodos privados pode ser uma indicação de que esses métodos devem ser transferidos para outra classe para promover a reutilização. Charles Miller expressou um ponto de vista semelhante em seu weblog :
se você tem um conjunto completo de testes para a interface exposta de uma classe (não-Privada), esses testes devem, por sua natureza, verificar que qualquer método privado dentro da classe também funciona. Se este não for o caso, ou se você tem um método privado tão complexo que precisa ser testado fora do contexto de seus chamadores públicos, eu consideraria isso um cheiro de código.
e Dave Thomas e Andy Hunt , em seu livro Pragmatic Unit Testing, write:
em geral, você não quer quebrar qualquer encapsulação por causa do teste (ou como a mãe costumava dizer, “não exponha suas partes privadas!”). Na maioria das vezes, você deve ser capaz de testar uma classe, exercitando seus métodos públicos. Se há uma funcionalidade significativa que está escondida atrás do acesso privado ou protegido, isso pode ser um sinal de aviso de que há outra classe lá lutando para sair. Acredito em todos estes conselhos. Na maioria das vezes, métodos privados podem ser testados de forma mais eficaz através da abordagem 1, indiretamente testando o nível de pacote, protegido, e métodos públicos que os chamam. Mas inevitavelmente, algumas pessoas em algumas situações sentirão que testar diretamente um método privado é a coisa certa a fazer.
no meu caso, eu tendem a criar muitos métodos de utilidade privada. Estes métodos de utilidade muitas vezes não fazem nada com dados de instância, eles apenas operam nos parâmetros passados e retornam um resultado. Eu crio tais métodos para tornar o método de chamada mais fácil de entender. É uma forma de gerir a complexidade da implementação da classe. Agora, se eu extrair o método privado de um método que já funciona e tem uma boa cobertura de teste de unidade, então esses testes de unidade existentes provavelmente serão suficientes. Não preciso de fazer mais testes de unidade só para o método privado. Mas se eu quiser escrever o método privado antes de seu método de chamada, e eu quero escrever os testes de unidade antes de escrever o método privado, eu estou de volta a querer testar diretamente o método privado. No caso dos métodos de utilidade privada, Eu não sinto meu desejo de testar diretamente os métodos é, como a FAQ JUnit disse, “uma indicação de que esses métodos devem ser movidos para outra classe para promover a reutilização.”Estes métodos são realmente necessários apenas na classe em que residem, e na verdade são muitas vezes chamados apenas por um outro método.
outra razão pela qual às vezes sinto a necessidade de testar métodos privados diretamente é que eu tendem a pensar em testes unitários como me ajudando a alcançar um sistema robusto, construindo esse sistema a partir de partes robustas. Cada parte é uma ” unidade “para a qual eu posso escrever” testes de unidade.”Os testes da unidade me ajudam a garantir que cada unidade está funcionando corretamente, o que por sua vez me ajuda a construir um sistema que funciona corretamente como um todo. A unidade primária que eu acho em termos de quando a programação em Java é a classe. Eu construo sistemas a partir de aulas, e testes de unidade me dão confiança de que minhas aulas são robustas. Mas, em certa medida, também sinto o mesmo em relação aos métodos privados dos quais componho package-access, protected, and public methods. Estes métodos privados são unidades que podem ser testadas individualmente. Estes testes unitários dão-me confiança de que os métodos privados estão a funcionar correctamente, o que me ajuda a construir métodos de acesso a pacotes, protegidos e públicos robustos.Como mencionei na introdução, dar aos métodos o acesso a pacotes foi a minha primeira abordagem para testar métodos privados com JUnit. Esta abordagem funciona muito bem, mas tem um pequeno custo. Quando eu vejo um especificador de acesso privado em um método, ele me diz algo que eu gosto de saber—que isso faz parte da implementação da classe. Eu sei que posso ignorar o método se eu estou apenas tentando usar a classe de outra classe no Pacote. Eu poderia descobrir isso sobre um método de acesso a pacotes olhando mais de perto para o nome, documentação e Código do método, mas a palavra private comunica isso de forma muito mais eficiente. Além disso, o principal problema que tenho com esta abordagem é filosófico. Embora eu não me importo de “quebrar encapsulação para o bem de testar”, como Dave e Andy diria, Eu apenas não me sinto bem sobre quebrar encapsulação de uma forma que muda a API Pacote-nível. Em outras palavras, embora eu esteja bastante entusiasmado para testar métodos não públicos de classes, ou seja, para criar testes de unidade “caixa branca”, eu prefiro a API das classes em teste, incluindo a API de nível pacote, não ser alterado para facilitar esses testes.
abordagem 3: Utilizar uma classe de ensaio aninhada
uma terceira abordagem ao ensaio de métodos privados consiste em nidificar uma classe de Ensaio estático dentro da classe de produção em ensaio. Uma vez que uma classe aninhada tem acesso aos membros privados de sua classe envolvente, ela seria capaz de invocar os métodos privados diretamente. A classe estática em si pode ser o acesso ao pacote, permitindo que ele seja carregado como parte do teste da caixa branca.
a desvantagem desta abordagem é que se você não quiser que a classe de teste aninhada seja acessível em seu arquivo JAR de implantação, você tem que fazer um pouco de trabalho extra para extra extra extra extra para extraí-lo. Além disso, algumas pessoas podem não gostar de ter o código de teste misturado no mesmo arquivo que o código de produção, embora outros possam preferir essa abordagem.
Approach 4: Use Reflection
the fourth approach to testing private methods was suggested to me by Vladimir R. Bossicard, who wrote JUnit Addons . Um dia ao almoço, Vladimir me esclareceu que a API
java.lang.reflect
incluía métodos que permitiam que o código cliente contornasse o mecanismo de proteção de acesso da máquina virtual Java. Ele também me disse que seu projeto JUnit Addons incluía uma classe,junitx.util.PrivateAccessor
, para ajudar a usar a API de reflexão para este propósito: para escrever testes de unidade que manipulam membros privados das classes em teste. A FAQ JUnit aponta para uma classe similar, chamadaPrivilegedAccessor
, escrita por Charlie Hubbard e Prashant Dhotke.uma vantagem de utilizar a abordagem de reflexão para testar métodos privados é que proporciona uma separação limpa do código de ensaio e do código de produção. Os ensaios não precisam de ser aninhados dentro da classe em ensaio, como na aproximação 3. Em vez disso, eles podem ser colocados ao lado dos outros testes que exercitam o nível de pacote e métodos públicos da classe. Além disso, você não precisa alterar a API da classe sob teste. Ao contrário da abordagem 2, os métodos privados podem permanecer privados. Ao contrário da abordagem 3, você não precisa adicionar nenhuma classe extra aninhada no nível de acesso ao pacote. A principal desvantagem desta abordagem é que o código de teste é muito mais descritivo porque ele usa a API de reflexão. Além disso, a refatoração IDEs como o Eclipse e o IntelliJ, normalmente, não são tão hábeis em alterar os nomes dos métodos de onde eles são referidos como
String
s passados para os métodos da API de reflexão. Então, se você mudar o nome do método privado com o seu IDE de refactoring, você ainda pode ter que fazer algumas alterações manualmente no código de teste.um exemplo
para dar um exemplo de um método privado que, na minha opinião, merece testes unitários directos, extraí alguma funcionalidade do método
main
da classeorg.suiterunner.Runner
.Runner.main
analisa os argumentos da linha de comandos e executa um conjunto de testes, activando opcionalmente a interface gráfica. O método I extraído,parseArgsIntoLists
, faz parte do trabalho de análise dos argumentos da linha de comando para a aplicação SuiteRunner. Agora, para testar o método público que chama este método privado, eu precisaria testarmain
. Principal, é claro, é toda a aplicação, o que torna o método bastante difícil de testar. Na verdade, Não tenho nenhum teste existente paramain
. Neste ponto, você pode estar se perguntando , se eu estava escrevendo testes primeiro no estilo de desenvolvimento orientado a testes, como eu acabei escrevendo código de análise que não tinha testes unitários? A principal razão é que a minha infecção do teste veio em etapas. Na verdade apanhei uma gripe de teste de unidade muito antes de ter ouvido falar de JUnit ou ler o teste infectado . Quando eu estava construindo aplicações Windows em C++, por exemplo, eu iria escrever um pouco de código para testar um método recém-implementado, em seguida, executar esse código e vê-lo executar, pisando através do método sob teste com o depurador. Este tipo de teste de unidade ajudou-me a alcançar a robustez, mas os próprios testes não verificaram o comportamento adequado. Eu próprio verifiquei o comportamento correcto, observando através do depurador. Os testes não eram automatizados, e por isso não os salvei para que pudessem ser executados mais tarde. Quando eu li Teste Infectado, eu imediatamente vi o valor de automatizar os testes e mantê-los como uma espécie de teste de regressão após a refatoração, mas por um longo tempo não fazia sentido para mim escrever os testes primeiro. Eu queria escrever os testes depois que eu implementei a funcionalidade, porque foi quando eu tinha executado os testes com o depurador. Uma razão secundária que eu não escrever testes primeiro ao desenvolver muito do SuiteRunner é que eu queria escrever testes do SuiteRunner com o próprio SuiteRunner, em um esforço para comer minha própria comida de cão. Até a API básica do SuiteRunner estar resolvida, eu não tinha o kit de ferramentas de teste que eu queria usar para escrever os testes.desde então, no entanto, o vírus de teste tem tomado um controle mais forte sobre mim, e eu agora prefiro escrever testes de unidade primeiro a maior parte do tempo. Eu prefiro escrever testes em primeiro lugar não tanto porque eu acho que eu acabo com desenhos mais limpos, que é geralmente promovido como o principal benefício do desenvolvimento orientado a testes. Em vez disso, eu prefiro escrever testes primeiro, porque eu acho que muitas vezes se eu mergulhar no código sob pressão, com a intenção de que eu vou escrever o teste mais tarde, o teste nunca realmente ser escrito. SuiteRunner em si tem muito poucos testes de unidade neste ponto por essa mesma razão. Aqui está o método
parseArgsIntoLists
:private static void parseArgsIntoLists(String args, List runpathList, List reportersList, List suitesList) { if (args == null || runpathList == null || reportersList == null || suitesList == null) { throw new NullPointerException(); } for (int i = 0; i < args.length; i++) { if (args.startsWith("-p")) { runpathList.add(args); runpathList.add(args); ++i; } else if (args.startsWith("-g")) { reportersList.add(args); } else if (args.startsWith("-o")) { reportersList.add(args); } else if (args.startsWith("-e")) { reportersList.add(args); } else if (args.startsWith("-f")) { reportersList.add(args); reportersList.add(args); ++i; } else if (args.startsWith("-r")) { reportersList.add(args); reportersList.add(args); ++i; } else if (args.startsWith("-s")) { suitesList.add(args); do { ++i; suitesList.add(args); } while (i + 1 < args.length); } else { throw new IllegalArgumentException("Unrecognized argument: " + args); } } }a linha de comando do SuiteRunner contém três tipos de informações usadas pelo SuiteRunner para executar testes: runpath, repórteres e suites. O método
parseArgsIntoLists
apenas passa pelos argumentos passados como uma matriz deString
s, e coloca cada argumento em uma das listas,runpathList
,reportersList
, esuitesList
.Antes de escrever um teste para este método privado, gostaria de perguntar se a minha vontade de escrever este teste de unidade representa um cheiro de código, como Charles Miller colocou no seu weblog? Indica queparseArgsIntoLists
deve ser transferido para outra classe para promover a reutilização, como sugere a FAQ JUnit? O Dave e o Andy diriam que é um sinal de aviso de que há outra turma a lutar para sair? Bem, talvez. Eu poderia concievably criar uma classeArgumentsParser
que só possui alguns métodos estáticos que realizam o trabalho de análise. Tanto a classeArgumentsParser
como os métodos que contém podem ser o acesso a pacotes, o que os tornaria fáceis de testar. Mas isso não me parece certo. Estes métodos são chamados apenas porRunner.main
. Parecem-me métodos privados. A única razão pela qual eu os moveria para uma classeArgumentsParser
é para poder testá-los. Na verdade, eu estaria usando a abordagem número 2: fazer o acesso ao pacote dos métodos privados.em vez disso, para este exemplo eu decidi tomar a abordagem número 4, e usar a reflexão. Olhei para Vladimir Bossicard’s
junitx.utils.PrivateAccessor
e Charlie Hubbard e Prashant DhotkePrivilegedAccessor
, mas decidi que nenhum deles me ajudou da maneira que eu queria. Por um lado, ambas as classes têm a capacidade de testar campos para se certificar de que eles são definidos corretamente. Até agora, nunca senti qualquer necessidade de aceder directamente a campos privados a partir de testes unitários. Só quero ser capaz de testar métodos de utilidade privada. O principal problema que tive com essas duas classes, no entanto, é como elas lidaram com as exceções que podem ser lançadas ao tentar invocar o método privado através da reflexão. Cada classe tem um ou mais métodos cujo trabalho é invocar um método com reflexão.PrivilegedAccessor
‘ s twoinvokeMethod
methods passes any exception back to its caller, including three checked exceptions declared in the lances clause:NoSuchMethodException
,IllegalAccessException
, andInvocationTargetException
. Em contrapartida, os dois métodosinvoke
capturamInvocationTargetException
e extraem e lançam a excepção-alvo, a excepção real lançada pelo método invocado. Ele então pega qualquer outra exceção, e atiraNoSuchMethodException
. Eu não gostei que o chamador dePrivilegedAccessor.invokeMethod
sempre precisaria lidar com as três excepções verificadas, porque eu pensei que a maneira geral de lidar com qualquer exceção seria deixar o teste falhar. Eu também estava preocupado que oPrivateAccessor.invoke
estava jogando fora informações potencialmente úteis stack trace em sua política de tratamento de exceção. O que eu realmente queria era um método que tentasse invocar um método privado com reflexão, que envolvesse qualquer exceção, além deInvocationTargetException
em um não controladoTestFailedException
. Na maioria das vezes, esta exceção faria com que o teste falhasse. Nos testes que esperavam uma exceção para ser lançada, a exceção contida emInvocationTargetException
poderia ser extraída e testada para a correção.Portanto, eu escrevi
invokeStaticMethod
. A chamadasetAccessible(true)
é o que permite que o método privado seja invocado de fora da classe. Uma implementação correspondenteinvokeStaticMethod
para uso com JUnit lançariaAssertionFailedError
em vez deTestFailedException
. Aqui está o código.:private static void invokeStaticMethod(Class targetClass, String methodName, Class argClasses, Object argObjects) throws InvocationTargetException { try { Method method = targetClass.getDeclaredMethod(methodName, argClasses); method.setAccessible(true); method.invoke(null, argObjects); } catch (NoSuchMethodException e) { // Should happen only rarely, because most times the // specified method should exist. If it does happen, just let // the test fail so the programmer can fix the problem. throw new TestFailedException(e); } catch (SecurityException e) { // Should happen only rarely, because the setAccessible(true) // should be allowed in when running unit tests. If it does // happen, just let the test fail so the programmer can fix // the problem. throw new TestFailedException(e); } catch (IllegalAccessException e) { // Should never happen, because setting accessible flag to // true. If setting accessible fails, should throw a security // exception at that point and never get to the invoke. But // just in case, wrap it in a TestFailedException and let a // human figure it out. throw new TestFailedException(e); } catch (IllegalArgumentException e) { // Should happen only rarely, because usually the right // number and types of arguments will be passed. If it does // happen, just let the test fail so the programmer can fix // the problem. throw new TestFailedException(e); } }em seguida, eu criei um método de conveniência que invoca o método particular privado que eu queria testar:
private static void invokeParseArgsIntoLists(String args, List runpathList, List reportersList, List suitesList) throws InvocationTargetException { // Purposely pass null values to the method, to make sure it throws // NullPointerException Class argClasses = {String.class, List.class, List.class, List.class }; Object argObjects = {args, runpathList, reportersList, suitesList }; invokeStaticMethod(Runner.class, "parseArgsIntoLists", argClasses, argObjects); }enfim, eu poderia escrever testes contra o método privado sem muito excesso de desordem, como este:
public void testParseArgsIntoLists() throws InvocationTargetException { String args = new String; List runpathList = new ArrayList(); List reportersList = new ArrayList(); List suitesList = new ArrayList(); try { invokeParseArgsIntoLists(null, runpathList, reportersList, suitesList); fail(); } catch (InvocationTargetException e) { // throw the InvocationTargetException unless the target // exception is NullPointerException, which is expected Throwable targetException = e.getTargetException(); if (!(targetException instanceof NullPointerException)) { throw e; } } try { invokeParseArgsIntoLists(args, null, reportersList, suitesList); fail(); } catch (InvocationTargetException e) { // throw the InvocationTargetException unless the target // exception is NullPointerException, which is expected Throwable targetException = e.getTargetException(); if (!(targetException instanceof NullPointerException)) { throw e; } } try { invokeParseArgsIntoLists(args, runpathList, null, suitesList); fail(); } catch (InvocationTargetException e) { // throw the InvocationTargetException unless the target // exception is NullPointerException, which is expected Throwable targetException = e.getTargetException(); if (!(targetException instanceof NullPointerException)) { throw e; } } try { invokeParseArgsIntoLists(args, runpathList, reportersList, null); fail(); } catch (InvocationTargetException e) { // throw the InvocationTargetException unless the target // exception is NullPointerException, which is expected Throwable targetException = e.getTargetException(); if (!(targetException instanceof NullPointerException)) { throw e; } } args = new String; args = "-p"; args = "\"mydir\""; args = "-g"; args = "-f"; args = "test.out"; args = "-s"; args = "MySuite"; runpathList.clear(); reportersList.clear(); suitesList.clear(); invokeParseArgsIntoLists(args, runpathList, reportersList, suitesList); verify(runpathList.size() == 2); verify(runpathList.get(0).equals(args)); verify(runpathList.get(1).equals(args)); verify(reportersList.size() == 3); verify(reportersList.get(0).equals(args)); verify(reportersList.get(1).equals(args)); verify(reportersList.get(2).equals(args)); verify(suitesList.size() == 2); verify(suitesList.get(0).equals(args)); verify(suitesList.get(1).equals(args)); args = new String; args = "-p"; args = "\"mydir\""; args = "-e"; args = "-o"; args = "-r"; args = "MyCustomReporter"; args = "-s"; args = "MySuite"; args = "MyOtherSuite"; runpathList.clear(); reportersList.clear(); suitesList.clear(); invokeParseArgsIntoLists(args, runpathList, reportersList, suitesList); verify(runpathList.size() == 2); verify(runpathList.get(0).equals(args)); verify(runpathList.get(1).equals(args)); verify(reportersList.size() == 4); verify(reportersList.get(0).equals(args)); verify(reportersList.get(1).equals(args)); verify(reportersList.get(2).equals(args)); verify(reportersList.get(3).equals(args)); verify(suitesList.size() == 3); verify(suitesList.get(0).equals(args)); verify(suitesList.get(1).equals(args)); verify(suitesList.get(2).equals(args)); args = new String; args = "-p"; args = "\"serviceuitest-1.1beta4.jar myjini http://myhost:9998/myfile.jar\""; args = "-g"; args = "-s"; args = "MySuite"; args = "MySecondSuite"; args = "MyThirdSuite"; args = "MyFourthSuite"; args = "MyFifthSuite"; args = "MySixthSuite"; runpathList.clear(); reportersList.clear(); suitesList.clear(); invokeParseArgsIntoLists(args, runpathList, reportersList, suitesList); verify(runpathList.size() == 2); verify(runpathList.get(0).equals(args)); verify(runpathList.get(1).equals(args)); verify(reportersList.size() == 1); verify(reportersList.get(0).equals(args)); verify(suitesList.size() == 7); verify(suitesList.get(0).equals(args)); verify(suitesList.get(1).equals(args)); verify(suitesList.get(2).equals(args)); verify(suitesList.get(3).equals(args)); verify(suitesList.get(4).equals(args)); verify(suitesList.get(5).equals(args)); verify(suitesList.get(6).equals(args)); }Conclusão
Abordagem 1, testar métodos privados indiretamente através do teste de nível de pacote, protegidos e métodos públicos que chamá-los, vai muitas vezes ser a melhor abordagem. Nos casos em que se pretende realmente testar directamente os métodos privados, utilizando a reflexão para testar os métodos privados, embora bastante pesados, proporciona-se a separação mais limpa do código de ensaio do código de produção e o menor impacto no código de produção. No entanto, se você não se importa de fazer esses métodos particulares que você quer testar o acesso ao pacote, você pode usar a abordagem 2. Ou se você não se importa de colocar uma classe de teste aninhada dentro da sua classe de produção sob teste, aproximação 3, pelo menos, deixá-lo manter os métodos privados privado.Não há uma resposta perfeita. Mas se você adotar a abordagem 4, você acabará com um punhado de métodos como
invokeStaticMethod
que você pode reutilizar. Uma vez que você escreve um método de conveniência, comoinvokeParseArgsIntoLists
, para um método privado, você pode escrever testes contra o método privado sem muita dificuldade.recursos
1. A API ServiceUI define uma forma padrão de anexar interfaces de usuário aos Serviços Jini:
http://www.artima.com/jini/serviceui/index.html2. Daniel Steinberg é atualmente o Editor-chefe da Java.NET:
http://www.java.net/3. Artima SuiteRunner é uma ferramenta livre de teste de código aberto e execução de JUnit:
http://www.artima.com/suiterunner/index.html4.Perguntas FAQ JUnit sobre testar métodos privados:
http://junit.sourceforge.net/doc/faq/faq.htm#tests_105. Testing Private Methods( Don’T Do It), A weblog post by Charles Miller:
http://fishbowl.pastiche.org/2003/03/28/testing_private_methods_dont_do_it6. Andy Hunt e Dave Thomas são os autores do Pragmatic Unit Testing, que está disponível na Pragmatic Store.
7. JUnit Addons é um conjunto de classes auxiliares para JUnit criado por Vladimar R. Bossicard:
http://sourceforge.net/projects/junit-addons
PrivateAccessor
é a classe do JUnit Addons que facilates testes de membros privados:
http://junit-addons.sourceforge.net/junitx/util/PrivateAccessor.html9.Classe de acesso privilegiado, que pode utilizar para aceder a membros privados:
http://groups.yahoo.com/group/junit/files/src/PrivilegedAccessor.java10. Test Driven Development by Example, by Kent Beck, describes the test-first technique:
http://www.amazon.com/exec/obidos/ASIN/0321146530/11. Teste de Infectados, por Kent Beck e Erich Gamma, introduzido JUnit para o mundo:
http://junit.sourceforge.net/doc/testinfected/testing.htmo Teste de Unidade de Métodos Privados, de um blog post sobre o nUnit por Ted Graham:
http://weblogs.asp.net/tgraham/archive/2003/12/31/46984.aspxSubvertendo do Java Proteção de Acesso para o Teste de Unidade, um O’Reilly OnJava.com artigo por Ross Burton:
http://www.onjava.com/pub/a/onjava/2003/11/12/reflection.htmlClasse
RunnerSuite
, a partir do qual os trechos de código neste artigo foram tiradas, aparece na íntegra aqui:
http://www.artima.com/suiterunner/privateExample.htmlPor que Nós Refatorado JUnit
http://www.artima.com/suiterunner/why.htmlArtima SuiteRunner Tutorial, a Construção de Conformidade e Testes de Unidade com Artima SuiteRunner:
http://www.artima.com/suiterunner/tutorial.htmlintrodução com Artima SuiteRunner, Como Executar o Exemplo Simples Incluído na Distribuição:
http://www.artima.com/suiterunner/start.htmlExecutado Testes JUnit com Artima SuiteRunner, como usar Artima SuiteRunner como JUnit corredor para executar o existente JUnit test suites:
http://www.artima.com/suiterunner/junit.htmlArtima SuiteRunner página inicial:
http://www.artima.com/suiterunner/index.htmlArtima SuiteRunner página de download (Você deve iniciar sessão Artima.com para baixar a versão):
http://www.artima.com/suiterunner/download.jspO SuiteRunner Fórum:
http://www.artima.com/forums/forum.jsp?forum=61Falar de volta!Tem uma opinião? Os leitores já postaram 26 comentários sobre este artigo. Porque não adicionas o teu?
Sobre o autor
Bill Venners é presidente da Artima Software, Inc. e editor – chefe da Artima.com ele é autor do livro, Dentro Da Máquina Virtual Java, uma pesquisa orientada a Programadores sobre a arquitetura e os internos da plataforma Java. His popular columns in JavaWorld magazine covered Java internals, object-oriented design, and Jini. O Bill tem estado activo na Comunidade Jini desde a sua criação. Ele liderou o projeto ServiceUI da Comunidade Jini que produziu a API ServiceUI. O ServiceUI tornou-se a forma padrão de fato de associar interfaces de usuário aos Serviços Jini, e foi o primeiro padrão comunitário Jini aprovado através do processo de decisão Jini. Bill também serve como um membro eleito do Comitê de Supervisão Técnica inicial da Comunidade Jini (COT), e neste papel ajudou a definir o processo de governança para a comunidade. Actualmente dedica a maior parte da sua energia à construção Artima.com em um recurso cada vez mais útil para os desenvolvedores.