Pergunta

Eu uso Assert.Fail muito ao fazer TDD. Normalmente, eu estou trabalhando em um teste em um tempo, mas quando eu começar idéias para coisas que eu quero implementar mais tarde eu escrever rapidamente um teste vazio onde o nome do método de teste indica o que eu quero implementar como uma espécie de lista de tarefas. Para se certificar de que eu não esqueça que eu pôr Assert.Fail () no corpo.

Ao tentar sair xUnit.Net eu achei que não tinha implementado Assert.Fail. Claro que você pode sempre Assert.IsTrue (false), mas isso não comunicar minha intenção também. Eu tenho a impressão Assert.Fail não foi implementada de propósito. É este má prática considerada? Se assim por que?


@ Martin Meredith Isso não é exatamente o que eu faço. Eu escrever um teste primeiro e depois implementar o código para torná-lo trabalho. Geralmente eu penso em vários testes de uma só vez. Ou eu penso sobre um teste para escrever quando estou trabalhando em outra coisa. Isso é quando eu escrevo um teste falha vazio para se lembrar. No momento em que eu começar a escrever o teste eu ordenadamente trabalho de teste primeiro.

@Jimmeh Que parece uma boa idéia. testes ignorados não falham, mas eles ainda aparecem em uma lista separada. Tem que tentar isso.

@ Matt Howells Boa ideia. NotImplementedException comunica intenção melhor do que assert.Fail () neste caso

@ Mitch Trigo Isso é o que eu estava procurando. Parece que foi deixado de fora para evitar que seja abusada de outra forma eu abusar dela.

Foi útil?

Solução

Para este cenário, ao invés de chamar Assert.Fail, eu faço o seguinte (em C # / NUnit)

[Test]
public void MyClassDoesSomething()
{
    throw new NotImplementedException();
}

É mais explícita do que um Assert.Fail.

Parece haver consenso geral de que é preferível usar afirmações mais explícitas do que Assert.Fail (). A maioria dos quadros tem que incluí-lo, porque embora eles não oferecem uma alternativa melhor. Por exemplo, NUnit (e outros) fornecer uma ExpectedExceptionAttribute de teste que alguns código lança uma classe particular de excepção. No entanto, a fim de teste que uma propriedade na exceção é definido para um valor particular, não se pode usá-lo. Em vez disso você tem que recorrer a Assert.Fail:

[Test]
public void ThrowsExceptionCorrectly()
{
    const string BAD_INPUT = "bad input";
    try
    {
        new MyClass().DoSomething(BAD_INPUT);
        Assert.Fail("No exception was thrown");
    }
    catch (MyCustomException ex)
    {
         Assert.AreEqual(BAD_INPUT, ex.InputString); 
    }
}

O método xUnit.net Assert.Throws torna esta uma mais limpa muito sem a necessidade de um método Assert.Fail. Ao não incluir um método Assert.Fail () xUnit.Net incentiva os desenvolvedores a encontrar e utilizar alternativas mais explícitas, e apoiar a criação de novas afirmações, quando necessário.

Outras dicas

Ele foi deliberadamente deixado de fora. Esta é a resposta de Brad Wilson a respeito de porque é que não há Assert.Fail ():

Nós não têm vista para isso, na verdade. Eu encontrar Assert.Fail é uma muleta que implica que há provavelmente um afirmação faltando. Às vezes é apenas a forma como o teste é estruturado e Às vezes é porque Assert poderia usar outra afirmação.

Eu sempre usei Assert.Fail () para lidar com casos em que você já detectados que um teste deve falhar por meio da lógica além da comparação valor simples. Como um exemplo:

try 
{
  // Some code that should throw ExceptionX
  Assert.Fail("ExceptionX should be thrown")
} 
catch ( ExceptionX ex ) 
{
  // test passed
}

Assim, a falta de Assert.Fail () nos olhares quadro como um erro para mim. Eu sugiro remendar a classe Assert para incluir um método falha () e, em seguida, submeter o patch para os desenvolvedores quadro, juntamente com o seu raciocínio para adicioná-lo.

Quanto à sua prática de criar testes que intencionalmente falham em seu espaço de trabalho, para lembrar-se de implementá-las antes de cometer, que parece ser uma prática muito bem para mim.

Eu uso MbUnit para o meu teste de unidade. Eles têm uma opção para ignorar testes, que aparecem como Orange (ao invés de verde ou vermelho) no conjunto de testes. Talvez xUnit tem algo semelhante, e que significa que você não tem sequer a colocar qualquer assert para o método, porque ele iria aparecer em uma cor irritantemente diferente tornando-se difícil de perder?

Editar:

Em MbUnit é da seguinte maneira:

[Test]
[Ignore]
public void YourTest()
{ } 

Este é o padrão que eu uso quando escrevendo um teste para o código que eu quero lançar uma exceção por design:

[TestMethod]
public void TestForException()
{
    Exception _Exception = null;

    try
    {
        //Code that I expect to throw the exception.
        MyClass _MyClass = null;
        _MyClass.SomeMethod();
        //Code that I expect to throw the exception.
    }
    catch(Exception _ThrownException)
    {   
        _Exception = _ThrownException
    }
    finally
    {
        Assert.IsNotNull(_Exception);
        //Replace NullReferenceException with expected exception.
        Assert.IsInstanceOfType(_Exception, typeof(NullReferenceException));
    }
}

IMHO esta é a melhor maneira de testar para exceções sobre o uso de Assert.Fail (). A razão para isto é que não só teste I para uma exceção sendo lançada em tudo, mas eu também teste para o tipo de exceção. Sei que esta é semelhante à resposta de Matt Howells, mas IMHO usando o último bloco é mais robusto.

Obviamente que ainda seria possível incluir outros métodos Assert para testar a cadeia de entrada exceções etc. Eu ficaria grato por seus comentários e opiniões sobre o meu padrão.

Pessoalmente, eu não tenho nenhum problema com o uso de um conjunto de testes como uma lista de tarefas como esta, desde que você, eventualmente, dar a volta a escrever o teste antes você implementar o código para passar.

Dito isto, eu costumava usar essa abordagem me, embora agora eu estou achando que isso me leva por um caminho de escrever muitos testes iniciais, que de uma maneira estranha é como o problema inverso de não escrever testes em tudo: você acaba de tomar decisões sobre o design um pouco cedo IMHO

.

Incidentalmente em MSTest, o modelo de teste padrão utiliza Assert.Inconclusive no final das suas amostras.

AFAIK quadro xUnit.NET pretende ser extremamente leve e sim, eles cortou falha deliberadamente, para incentivar o desenvolvedor para usar uma condição de falha explícita.

palpite: retenção Assert.Fail se destina a impedir que você pensar que uma boa maneira de código de teste de escrita é como uma enorme pilha de espaguete levando a um Assert.Fail nos casos ruins. [Edit para adicionar: respostas de outras pessoas confirmam amplamente este, mas com citações]

Uma vez que não é o que você está fazendo é, é possível que xUnit.Net está sendo super-protetor.

Ou talvez eles só acho que é tão raro e tão unorthogonal a ser desnecessário.

Eu prefiro para implementar uma função chamada ThisCodeHasNotBeenWrittenYet (na verdade algo mais curto, para facilitar a digitação). Não é possível comunicar a intenção mais claramente do que isso, e você tem um termo de pesquisa preciso.

Se isso falhar, ou não é implementado (para provocar um erro de vinculador), ou é uma macro que não compilar, pode ser alterado para se adequar a sua preferência atual. Por exemplo, quando você quer executar algo que é acabado, você quer um fracasso. Quando você está sentado para se livrar de todos eles, você pode querer um erro de compilação.

Com o código de boa eu costumo fazer:

void goodCode() {
     // TODO void goodCode()
     throw new NotSupportedOperationException("void goodCode()");
}

Com o código de teste que eu costumo fazer:

@Test
void testSomething() {
     // TODO void test Something
     Assert.assert("Some descriptive text about what to test")
}

Se estiver usando JUnit, e não quero chegar a falha, mas o erro, então eu costumo fazer:

@Test
void testSomething() {
     // TODO void test Something
     throw new NotSupportedOperationException("Some descriptive text about what to test")
}

Cuidado Assert.Fail e sua influência corruptora para fazer os desenvolvedores a escrever testes tolas ou quebrados. Por exemplo:

[TestMethod]
public void TestWork()
{
    try {
        Work();
    }
    catch {
        Assert.Fail();
    }
}

Isso é bobagem, porque o try-catch é redundante. Um teste falha se ele lança uma exceção.

Além disso

[TestMethod]
public void TestDivide()
{
    try {
        Divide(5,0);
        Assert.Fail();
    } catch { }
}

Esta é quebrado, o teste vai sempre passar, independentemente do resultado da função Divide. Mais uma vez, um teste falhar se e somente se ele lança uma exceção.

Por que você usaria Assert.Fail para dizer que uma exceção deve ser jogado? Isso é desnecessário. Porque não usar o atributo ExpectedException?

Se você estiver escrevendo um teste que apenas falha e, em seguida, escrever o código para ele, em seguida, escrever o teste. Isto não é Test Driven Development.

Tecnicamente, Assert.fail () não deve ser necessária se você estiver usando test driven development corretamente.

Você já pensou em usar uma lista de tarefas, ou a aplicação de uma metodologia GTD ao seu trabalho?

MS teste tem Assert.Fail () , mas também tem Assert.Inconclusive () . Eu acho que o uso mais apropriado para Assert.Fail () é se você tem alguma lógica em linha que seria estranho para colocar em uma afirmação, embora eu não posso nem pensar em qualquer bons exemplos. Para a maior parte, se a estrutura de teste suportes algo diferente de Assert.Fail (), em seguida, usá-lo.

Eu acho que você deve perguntar a si mesmos o que (inicial) os testes devem fazer.

Primeiro, você escreve um (conjunto de) teste sem implmentation. Talvez, também os cenários de dia chuvoso.

Todos os testes devem falhar, para ser testes corretos: Então você quer conseguir duas coisas: 1) Verifique se sua implementação está correta; 2) Verifique se os testes de unidade estão corretos.

Agora, se você faz TDD adiantado, você quer executar todos os testes, também, as peças da JNI. O resultado da sua execução total do teste passa se: 1) Todo o material implementado sucede 2) Todos os JNI coisas falha

Afinal, seria uma ommision teste de unidade, se os testes de unidade consegue enquanto não há nenhuma implementação, não é?

Você quer acabar com algo de um mail do seu teste de integração contínua que verifica todas implementadas e não implementado código, e é enviado se algum código implementado falhar, ou qualquer código não foi implementado com êxito. Ambos são resultados indesejados.

Basta escrever um [ignorar] testes não vai fazer o trabalho. Nem, um afirma que pára uma primeira falha assert, não correndo outras linhas de testes no teste.

Agora, como para conseguir isso, então? Eu acho que requer alguma organização mais avançada do seu teste. E isso requer algum outro mecanismo, em seguida, afirma a atingir estes objectivos.

Eu acho que você tem que dividir seus testes e criar alguns testes que completamente executados, mas deve falhar, e vice-versa.

As ideias são para dividir seus testes ao longo de vários conjuntos, o uso de agrupamento de testes (testes encomendados em mstest pode fazer o trabalho).

Ainda assim, uma compilação CI que mails se não todos os testes no departamento JNI falhar não é fácil e simples.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top