2017-08-21 1 views
3

J'utilise Moq dans .net core (1.1) et j'ai un peu de temps à comprendre ce comportement comme tous les exemples sur interweb souligne le fait que cela devrait fonctionner sans problèmes.Mock renvoie une valeur nulle lorsque ReturnResult est un objet personnalisé mais fonctionne comme prévu lorsqu'il s'agit d'un type primitif booléen

J'ai déjà essayé avec:

  • Returns (Task.FromResult (...)
  • retours (Task.FromResult (...)
  • ReturnsAsync (...)

Mocking une interface IHttpClien t pour envelopper PostAsync, PutAsync et GetAsync. Tous ces éléments renvoient un objet ApiResponse.

var mockClient = new Mock<IHttpClient>(); 

ne fonctionne pas:

mockClient.Setup(x => x.PostAsync(url, JsonConvert.SerializeObject(body), null)) 
            .Returns(Task.FromResult(new ApiResponse())); 

PostSync définition:

public async Task<ApiResponse> PostAsync(string url, string body, string authToken = null) 

fonctionne:

mockClient.Setup(x => x.PostAsync(url, JsonConvert.SerializeObject(body), null)) 
            .Returns(Task.FromResult(bool)); 

PostSync définition:

public async Task<bool> PostAsync(string url, string body, string authToken = null) 

Utilisation:

var api = new ApiService(mockClient.Object); 
var response = api.LoginAsync(body.Username, body.Password); 

MISE À JOUR

[Fact] 
public async void TestLogin() 
{ 
    var mockClient = new Mock<IHttpClient>(); 
    mockClient.Setup(x => x.PostAsync(url, JsonConvert.SerializeObject(body), null)).Returns(Task.FromResult(new ApiResponse())); 

    var api = new ApiService(mockClient.Object); 
    var response = await api.LoginAsync(body.Username, body.Password); 
    Assert.IsTrue(response); 
} 

Type de retour:

public class ApiResponse 
{ 
    public string Content { get; set; } 

    public HttpStatusCode StatusCode { get; set; } 

    public string Reason { get; set; } 
} 

LoginAsync:

public async Task<bool> LoginAsync(string user, string password) 
{ 
    var body = new { Username = user, Password = password }; 
    try 
    { 
     var response = await _http.PostAsync(_login_url, JsonConvert.SerializeObject(body), null); 
     return response .State == 1; 
    } 
    catch (Exception ex) 
    { 
     Logger.Error(ex); 
     return false; 
    } 
} 

PostAsync:

public async Task<object> PostAsync(string url, string body, string authToken = null) 
{ 
    var client = new HttpClient(); 
    var content = new StringContent(body, Encoding.UTF8, "application/json"); 
    var response = await client.PostAsync(new Uri(url), content); 
    var resp = await response.Result.Content.ReadAsStringAsync(); 
    return new ApiResponse 
    { 
     Content = resp, 
     StatusCode = response.Result.StatusCode, 
     Reason = response.Result.ReasonPhrase 
    }; 
} 

Répondre

3

En supposant une méthode simple à l'essai comme celui-ci sur la base exemple minimal fourni ci-dessus.

public class ApiService { 
    private IHttpClient _http; 
    private string _login_url; 

    public ApiService(IHttpClient httpClient) { 
     this._http = httpClient; 
    } 

    public async Task<bool> LoginAsync(string user, string password) { 
     var body = new { Username = user, Password = password }; 
     try { 
      var response = await _http.PostAsync(_login_url, JsonConvert.SerializeObject(body), null); 
      return response.StatusCode == HttpStatusCode.OK; 
     } catch (Exception ex) { 
      //Logger.Error(ex); 
      return false; 
     } 
    } 
} 

Le test suivant fonctionne lorsqu'il est configuré correctement

[Fact] 
public async Task Login_Should_Return_True() { //<-- note the Task and not void 
    //Arrange 
    var mockClient = new Mock<IHttpClient>(); 
    mockClient 
     .Setup(x => x.PostAsync(It.IsAny<string>(), It.IsAny<string>(), null)) 
     .ReturnsAsync(new ApiResponse() { StatusCode = HttpStatusCode.OK }); 

    var api = new ApiService(mockClient.Object); 

    //Act 
    var response = await api.LoginAsync("", ""); 

    //Assert 
    Assert.IsTrue(response); 
} 

Ce qui précède est juste à des fins démonstratives seulement de montrer qu'il peut fonctionner à condition que le test est correctement configuré et exercé basée sur le comportement attendu.

Prenez le temps de passer en revue le Moq quick start pour avoir une meilleure compréhension de l'utilisation du cadre.

+0

D'accord. Pour autant que je sache, la différence clé semble être dans la configuration où j'ai déduit les types de paramètres vs votre configuration "correcte". Je suppose que les hypothèses peuvent vraiment faire un âne. Bien aimerait creuser plus profondément dans pourquoi ce que j'ai utilisé était "incorrect". ** Beaucoup apprécié! ** – Walaitki

+0

@Walaitki moq répond directement à ce que vous configurez à attendre. Bien que mon exemple soit très simple, vous devez configurer le moq pour vous attendre au comportement que vous voulez tester. Si vous ne fournissez pas le comportement que le simulacre attend, il ne fonctionnera pas comme prévu. Pour dire exactement pourquoi le vôtre n'a pas fonctionné, il n'y a pas assez de détails dans la question. trop de pièces manquantes au puzzle. pourrait quelque chose d'aussi simple et un espace mal placé dans une chaîne. – Nkosi

+0

'It.IsAny' un exemple tout à fait dangereux ** démonstratif **, vous savez :) – VMAtm