tl; dr
No Pivotal, escrevemos Cedar porque usamos e amamos o Rspec em nossos projetos Ruby. O cedro não pretende substituir ou competir com o OCUnit; Ele visa trazer a possibilidade de teste no estilo BDD para o Objective C, assim como o Rspec foi pioneiro no teste no estilo BDD no Ruby, mas não eliminou o Test :: Unit. Escolher um ou outro é em grande parte uma questão de preferências de estilo.
Em alguns casos, projetamos o Cedar para superar algumas deficiências na maneira como o OCUnit funciona para nós. Especificamente, queríamos poder usar o depurador em testes, executar testes na linha de comando e nas compilações de IC e obter uma saída de texto útil dos resultados dos testes. Essas coisas podem ser mais ou menos úteis para você.
Resposta longa
A decisão entre duas estruturas de teste, como Cedar e OCUnit (por exemplo), se resume a duas coisas: estilo preferido e facilidade de uso. Vou começar com o estilo, porque isso é simplesmente uma questão de opinião e preferência; a facilidade de uso tende a ser um conjunto de compensações.
As considerações de estilo transcendem a tecnologia ou o idioma que você usa. O teste de unidade no estilo xUnit existe há muito mais tempo do que o teste no estilo BDD, mas o último ganhou rapidamente popularidade, principalmente devido ao Rspec.
A principal vantagem dos testes no estilo xUnit é sua simplicidade e ampla adoção (entre desenvolvedores que escrevem testes de unidade); praticamente qualquer idioma em que você considere escrever código possui uma estrutura no estilo xUnit disponível.
As estruturas no estilo BDD tendem a ter duas diferenças principais quando comparadas ao estilo xUnit: como você estrutura o teste (ou especificações) e a sintaxe para escrever suas afirmações. Para mim, a diferença estrutural é o principal diferenciador. Os testes xUnit são unidimensionais, com um método setUp para todos os testes em uma determinada classe de teste. As classes que testamos, no entanto, não são unidimensionais; geralmente precisamos testar ações em vários contextos diferentes e potencialmente conflitantes. Por exemplo, considere uma classe simples ShoppingCart, com um método addItem: (para os fins desta resposta, usarei a sintaxe do Objective C). O comportamento deste método pode diferir quando o carrinho está vazio, comparado a quando o carrinho contém outros itens; pode ser diferente se o usuário tiver inserido um código de desconto; pode ser diferente se o item especificado puder " • ser enviado pelo método de envio selecionado; etc. Como essas condições possíveis se cruzam, você acaba com um número geometricamente crescente de contextos possíveis; nos testes no estilo xUnit, isso geralmente leva a muitos métodos com nomes como testAddItemWhenCartIsEmptyAndNoDiscountCodeAndShippingMethodApplies. A estrutura das estruturas no estilo BDD permite que você organize essas condições individualmente, o que eu acho que facilita a cobertura de todos os casos, além de encontrar, alterar ou adicionar condições individuais. Como um exemplo, usando a sintaxe Cedar, o método acima ficaria assim: nos testes no estilo xUnit, isso geralmente leva a muitos métodos com nomes como testAddItemWhenCartIsEmptyAndNoDiscountCodeAndShippingMethodApplies. A estrutura das estruturas no estilo BDD permite que você organize essas condições individualmente, o que eu acho que facilita a cobertura de todos os casos, além de encontrar, alterar ou adicionar condições individuais. Como um exemplo, usando a sintaxe Cedar, o método acima ficaria assim: nos testes no estilo xUnit, isso geralmente leva a muitos métodos com nomes como testAddItemWhenCartIsEmptyAndNoDiscountCodeAndShippingMethodApplies. A estrutura das estruturas no estilo BDD permite que você organize essas condições individualmente, o que eu acho que facilita a cobertura de todos os casos, além de encontrar, alterar ou adicionar condições individuais. Como um exemplo, usando a sintaxe Cedar, o método acima ficaria assim:
describe(@"ShoppingCart", ^{
describe(@"addItem:", ^{
describe(@"when the cart is empty", ^{
describe(@"with no discount code", ^{
describe(@"when the shipping method applies to the item", ^{
it(@"should add the item to the cart", ^{
...
});
it(@"should add the full price of the item to the overall price", ^{
...
});
});
describe(@"when the shipping method does not apply to the item", ^{
...
});
});
describe(@"with a discount code", ^{
...
});
});
describe(@"when the cart contains other items, ^{
...
});
});
});
Em alguns casos, você encontrará contextos que contêm os mesmos conjuntos de asserções, que podem ser SECADOS usando contextos de exemplo compartilhado.
A segunda principal diferença entre estruturas no estilo BDD e estruturas no estilo xUnit, sintaxe de asserção (ou "correspondente"), simplesmente torna o estilo das especificações um pouco melhor; algumas pessoas realmente gostam, outras não.
Isso leva à questão da facilidade de uso. Nesse caso, cada estrutura tem seus prós e contras:
O OCUnit existe há muito mais tempo que o Cedar e é integrado diretamente ao Xcode. Isso significa que é simples criar um novo alvo de teste e, na maioria das vezes, colocar os testes em funcionamento "simplesmente funciona". Por outro lado, descobrimos que, em alguns casos, como a execução em um dispositivo iOS, era quase impossível fazer os testes do OCUnit. A configuração das especificações do Cedar exige um pouco mais de trabalho do que os testes do OCUnit, pois você obtém a biblioteca e o vincula a ela (nunca uma tarefa trivial no Xcode). Estamos trabalhando para facilitar a instalação e todas as sugestões são bem-vindas.
O OCUnit executa testes como parte da compilação. Isso significa que você não precisa executar um executável para fazer seus testes; se algum teste falhar, sua construção falhará. Isso torna o processo de execução de testes um passo mais simples, e a saída de teste entra diretamente na janela de saída da compilação, o que facilita a visualização. Optamos por incluir as especificações do Cedar em um executável, que você executa separadamente por alguns motivos:
- Queríamos poder usar o depurador. Você executa as especificações do Cedar como faria com qualquer outro executável, para poder usar o depurador da mesma maneira.
- Queríamos testes fáceis de logar no console. Você pode usar o NSLog () nos testes do OCUnit, mas a saída entra na janela de construção, na qual é necessário desdobrar a etapa de construção para lê-la.
- Queríamos uma leitura fácil dos relatórios de teste, tanto na linha de comando quanto no Xcode. Os resultados do OCUnit aparecem bem na janela de compilação no Xcode, mas a criação a partir da linha de comando (ou como parte de um processo de IC) resulta na saída de teste misturada com muitas outras saídas de compilação. Com fases separadas de construção e execução, o Cedar separa a saída para facilitar a localização da saída de teste. O corredor de teste padrão Cedar copia o estilo padrão de impressão "." para cada especificação aprovada, "F" para especificações com falha etc.) O Cedar também tem a capacidade de usar objetos repórter personalizados, para que você possa produzir resultados da maneira que desejar, com um pouco de esforço.
O OCUnit é a estrutura oficial de teste de unidade do Objetivo C e é suportada pela Apple. A Apple possui basicamente recursos ilimitados, portanto, se eles querem algo feito, serão feitos. E, afinal, esta é a sandbox da Apple em que estamos jogando. O outro lado dessa moeda, no entanto, é que a Apple recebe da ordem de um bajilhão de solicitações de suporte e relatórios de erros todos os dias. Eles são extraordinariamente bons em lidar com todos eles, mas podem não ser capazes de lidar com problemas relatados imediatamente ou de maneira alguma. O Cedar é muito mais recente e menos elaborado que o OCUnit, mas se você tiver dúvidas, problemas ou sugestões, envie uma mensagem para a lista de discussão do Cedar (cedar-discuss@googlegroups.com) e faremos o possível para ajudá-lo. Além disso, fique à vontade para copiar o código do Github (github.com/pivotal/cedar) e adicionar o que achar que está faltando.
A execução de testes do OCUnit em dispositivos iOS pode ser difícil. Honestamente, eu não tentei isso por algum tempo, por isso pode ter ficado mais fácil, mas na última vez que tentei, simplesmente não pude fazer os testes do OCUnit para que qualquer funcionalidade do UIKit funcionasse. Quando escrevemos o Cedar, tínhamos certeza de que poderíamos testar o código dependente do UIKit no simulador e nos dispositivos.
Finalmente, escrevemos o Cedar para testes de unidade, o que significa que não é realmente comparável a projetos como o UISpec. Já faz um bom tempo que eu tentei usar o UISpec, mas entendi que ele estava focado principalmente na condução programada da interface do usuário em um dispositivo iOS. Decidimos especificamente não tentar que o Cedar suporte esses tipos de especificações, já que a Apple estava (na época) prestes a anunciar o UIAutomation.