Classes de teste de unidade com funcionalidade online

23

Ao testar unidades de funções de uma classe que possui funções particulares que exigem funcionalidade online. Como alguém iria testá-lo?

Por exemplo:

public class Foo
{
    public int methodA()
    {
         int val = goOnlineToGetVal();

         return val;
    }

    private int goOnlineToGetVal()
    {
        CloudService c = new CloudService();
        int oval = c.getValueFromService();
        return oval;
    }
}

Se eu testasse a função: 'methodA ()', tentaria usar 'goOnlineToGetVal ()', que por sua vez tentaria ficar online, no entanto, se esse teste fosse feito sem funcionalidade. Como eu cobria cerca de 100% de cobertura da aula sem ficar on-line?

Ben enlouqueceu Euden
fonte
Seu método chama a API da nuvem ou também funciona?
Winston Ewert 15/09
4
Injeção de dependência ?
PhaDaPhunk 16/09

Respostas:

76

new CloudService()

E aí está o seu problema.

O design moderno do OO recomenda que esse tipo de dependência seja passado em vez de construído diretamente. Isso pode ser passado para a própria função ou para a classe no momento da construção. Também pode ser capturado ou agregado por um contêiner de Inversão de controle, se esse tipo de complexidade for justificado.

Nesse ponto, torna-se bastante trivial passar em um serviço falso / falso para fornecer seus dados "online" durante o teste. Melhor ainda, ele permite que seu software seja suficientemente flexível, para que você possa se adaptar rapidamente caso algum cliente (governamental?) Apareça e não queira usar a nuvem para seus valores. Ou você deseja despejar um provedor de nuvem para outro. Ou...

Telastyn
fonte
7
Eu acho que fiquei muito mais perto de entender o que diabos é a injeção de dependência.
marczellm
Onde é o melhor lugar para criar todas as instâncias que meu aplicativo precisa? O mais próximo possível do topo do meu aplicativo? Você só pode aplicar injeção de dependência até o momento; em algum momento, você precisará criar as instâncias por conta própria, em vez de passar como argumentos.
Paul
3
@ Paul - Depende. Na minha experiência, os aplicativos costumam parecer árvores binárias - uma classe / função / módulo une duas para fornecer um comportamento mais complexo. Uma dessas classes de "cola" é a que especifica a implementação concreta, que por sua vez é usada por algo acima que a cola com outra coisa, que por sua vez ... até chegar ao ponto de entrada que cola as peças grandes coerentemente. O "melhor" lugar é o lugar que permite que seu código faça o que precisa, sem fazê-lo ou saber sobre coisas que não deveria. Isso varia.
Telastyn 16/09/14
2
@Paul Normalmente, seu aplicativo é dividido entre uma "biblioteca", que é diretamente testada e deve usar esse tipo de injeção de dependência e código específico do aplicativo. O último geralmente se resume a alguma GUI, serviço da Web ou interface de linha de comando que chama diretamente a biblioteca com dados fornecidos pelo usuário. Essencialmente, o código específico do aplicativo criará as implementações concretas que a biblioteca injetada em dependência espera.
Darkhogg
@Paul Dê uma olhada em contêineres IoC como Castle Windsor, StructureMap, Ninject e Unity. Eles não são de forma a única maneira de fazer a injeção de dependência, mas eles podem ser muito informativo em termos de pensamento sobre a construção de um gráfico de objeto, de cima para baixo
Ben Aaronson
37

Eu implementaria assim:

public class Foo
{
    private ICloudService cloudService;

    public Foo(ICloudService s)
    {
       cloudService=s;
    }

    public int methodA()
    {
         int val = goOnlineToGetVal();

         return val;
    }

    private int goOnlineToGetVal()
    {
        int oval = cloudService.getValueFromService();
        return oval;
    }
}

A interface ICloudServicepode ser implementada com uma simulação para teste ou com o serviço de nuvem "real". Quando a instanciação new CloudService()é obrigatória para cada chamada de getValueFromService, ou CloudServiceé de uma API de terceiros que não pode ser alterada, implemente um wrapper, derivando ICloudServicee fazendo as chamadas apropriadas.

Doc Brown
fonte
1
Este é definitivamente o caminho a seguir. Existem bibliotecas de classes que podem simular uma interface, fornecendo controle absoluto do teste.
22813 Greg Greghardhardt