Pergunta

Eu quero lidar com uma exceção ManagementException por apenas um ErrorCode específica e estou tendo dificuldade para escrever o teste de unidade para isso. Normalmente, eu iria escrever o teste de modo que é algo como o seguinte:

Searcher search = MockRepository.GenerateMock<Searcher>(); 
// wrapper for ManagementObjectSearcher

...

search.Expect(s => s.Get()).Throw(new ManagementException());

...

No entanto, isso não define o ErrorCode para o que eu quero em particular, de fato ManagementException não tem um construtor que define esse valor.

Como isso pode ser feito?

(Note que estou usando RhinoMocks como meu quadro zombando mas eu estou supondo que este é quadro independente;. Tudo que eu preciso de saber aqui é como criar um ManagementException que tem um valor específico ErrorCode Também eu encontrei algumas referências a um método System.Management.ManagementException.ThrowWithExtendedInfo(ManagementStatus errorCode) online, mas isso não parece ser acessível ao público).

Foi útil?

Solução

O mínimo esforço para superar este obstáculo seria um método auxiliar / utilidade estática que usa reflexão para cortar-slot no código de erro necessário. Usando o mais excelente refletor, vejo que há um campo privado "errorCode", que só é definida através ctors internos definidos em ManagementException. Assim:)

public static class EncapsulationBreaker
   {
      public static ManagementException GetManagementExceptionWithSpecificErrorCode(ManagementStatus statusToBeStuffed)
      {
         var exception = new ManagementException();
         var fieldInfo = exception.GetType().GetField("errorCode", 
            BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField | BindingFlags.DeclaredOnly);
         fieldInfo.SetValue(exception, statusToBeStuffed);
         return exception;
      }
   }

Verificado que ele funciona

[Test]
      public void TestGetExceptionWithSpecifiedErrorCode()
      {
         var e = EncapsulationBreaker.GetManagementExceptionWithSpecificErrorCode(ManagementStatus.BufferTooSmall);
         Assert.AreEqual(ManagementStatus.BufferTooSmall, e.ErrorCode);
      }

Embora Eu geralmente desaprovam reflexão em testes , este é um dos raros casos onde é necessário / útil.
HTH

Outras dicas

Derivar uma classe de ManagementException e esconder a implementação do código de erro com o seu próprio. Ter o seu retorno simulada esta classe.

Tenha um método ou classe muito simples e pequeno que pega essa exceção e recebe o código de erro de fora e passa isso para a classe real que faz o trabalho. Em teste, substituir esse código com o passar diretamente para a classe real o que você deve passar quando você começa a código de erro.

A maneira mais óbvia é a subclasse a exceção, mas se isso não funcionar, então o código que chama-lo, e imediatamente lança sua própria exceção que lhe permite expor que o código seria outra opção.

Eu subclasse ManagementException e na subclasse substituir o getter ErrorCode (se os níveis de proteção normais impedi-lo de fazer isso, talvez introspecção pode chegar mais perto). Qualquer código que manipula ManagementException mas nunca ouviu falar sobre sua subclasse específica deve lidar com sua subclasse "como se" fosse o ManagementException que você está tentando simular para fins de teste, depois de tudo.

Editar : é concebível que ErrorCode simplesmente não pode ser substituído (eu odeio línguas que são tão rígidas que eles podem parar de testar, desta forma, mas não pode negar que eles existem ;-). Neste caso, Dependency Injection pode ainda poupar -. DI é um dos meus modelos preferidos para testes

O propósito de DI em testes é dissociar o código em teste de hipóteses rígidas que inibiriam a capacidade de teste - e isso é só o que temos aqui, embora de uma forma incomum. Seu código em teste atualmente faz, dizer, x.ErrorCode para obter o código de erro de exceção x. Muito bem, ele deve, em seguida, fazer, em vez disso, getErrorCode(x) onde getErrorCode é um delegado que normalmente só faz return x.ErrorCode; e deve ter um setter para o delegado getErrorCode, de modo que para fins de teste, você pode alterá-lo para um delegado que faz return 23 (ou qualquer valor de erro código que você deseja simular para testar).

Os detalhes podem variar, mas lata injeção de dependência (entre outras coisas) ajudar a compensar alguns tipos de rigidez excessiva em objetos que você inevitavelmente começar a partir do sistema (ou de outras bibliotecas & C que você não pode modificar diretamente), como neste exemplo.

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