NSubstitute - Simulando retorno de um método async
Em testes unitários um stub é um tipo de fake usado para simular o código de uma dependência do objeto ou tema que esta sendo testado (subject under test ou sut). Em meus projetos adotei o NSubstitute como ferramenta para criação de fakes. Ele possibilita configurar de maneira bem simples um objeto para que ele tenha retorno específicos as chamadas de seus métodos.
A API do NSub é bem simples. Para criar um stub de uma interface por exemplo, basta chamar o método For<T>
da classe Substitute, que se escreve de maneira fluente:
var stub = Substitute.For<IUserService>();
A interface em questão tem a seguinte declaração:
public interface IUserService
{
Task<string> GetTokenAsync(bool legacy = true);
Task<User> GetUserAsync();
bool IsSignedIn { get; }
}
O NSub vai criar um objeto com um classe anonima implementando a interface, com uma implementação padrão para cada um dos seus elementos. Supondo que você queira que a propriedade IsSignedIn
retorne true
quando for chamada, bastaria configurar dessa forma:
stub.IsSignedIn.Returns(true);
A mesma técnica se aplica para métodos, porém note que a interface de exemplo tem uma particularidade: seus métodos assíncronos. Então me deparei com um cenário onde o método precisava retornar um valor específico em uma chamada com await
. Como simular isso?
Como métodos assíncronos na verdade retornam um objeto do tipo Task<T>
, é necessário um pequeno ajuste no método Returns
para que ele receba uma Task com o resultado desejado inserido:
stub.GetTokenAsync(Arg.Any<bool>())
.Returns(
Task.FromResult("TEST TOKEN")
);
Essa técnica funcionará independente do framework de testes que estiver usando (xUnit, NUnit, MSTest, etc.), pois é própria do NSubstitute. Creio que seja simples transcrever para outros frameworks de fakes como o Moq.