O teste de unidade com NSURLConnection
-
03-07-2019 - |
Pergunta
Eu quero testar um pedaço de código que rede usa (a classe NSURLConnection
, para ser mais específico). O código (vamos chamá-lo NetworkManager
) parece um pouco com isto:
- (id) buildConnection
{
// some more code and then:
return [NSURLConnection …];
}
- (void) startNetworkSync
{
id connection = [self buildConnection];
//…
}
No teste de unidade que eu gostaria de se livrar da rede, ou seja. substituir o objecto NSURLConnection
por uma falsa. Como posso fazer isso?
Eu tentei criar um mock parcial do NetworkManager
que substituiria o método buildConnection
por um topo. O problema é que as simulações parciais feitos por OCMock mensagens somente stub do mundo do lado de fora -. envio buildConnection
do startNetworkSync
invoca o método original, não o toco
Eu também tentei macaco-remendar a classe NetworkManager
através de uma categoria. Isso funciona, eu posso facilmente substituir o método buildConnection
por outro código e substituir o NSURLConnection
real com um topo. O problema é que eu não encontrei nenhuma maneira simples que eu poderia obter a conexão arrancado no teste -. A conexão é uma parte privada da NetworkManager
Então eu poderia subclasse o NetworkManager
, substituir o método buildConnection
e adicionar uma variável de instância mais um assessor para a conexão criada. Este parece ser um monte de código, no entanto.
Como você resolveria isso? Eu estou procurando uma solução que mantém o design de classe NetworkManager
limpo e não requer muita magia nem muito código no teste.
Solução
Este é o tipo de injeção de dependência coisa é projetado para resolver; se você usar startNetworkSyncWithConnection:(NSURLConnection*)
em vez disso você pode facilmente testar o método com uma conexão falsa. Se você não quiser alterar a API para os seus clientes que você ainda poderia manter startNetworkSync
como um invólucro que não faz nada mas a chamada que o novo método com [self buildConnection]
como argumento.
Outras dicas
Eu modifiquei OCMock para suportar simulações parciais reais, consulte o repo no GitHub .
Outra solução que tenho usado recentemente é completamente abstrato da interface de rede. Se a classe precisa de alguns dados da rede, ele provavelmente interage com algum serviço de servidor que pode ser explicitamente modelado como um protocolo:
@protocol SomeNetworkService
- (NSArray*) allAvailableFoos;
- (void) insertNewFoo: (Foo*) foo;
@end
E então você vai ter uma implementação HTTP real e um teste. Isso significa mais trabalho, mas também muito melhor testabilidade. Os testes são menos frágil e muito mais conveniente, uma vez que a camada de rede de testes pode fazer o que você precisa.