C# 当ReturnResult是自定义对象时,Mock返回null值,但当它是基元类型bool时,它会按预期工作
我正在使用.NETCore(1.1)中的Moq,并且花了一点时间来理解这种行为,因为interweb上的所有示例都表明了这样做应该不会有任何问题 我已经尝试过:C# 当ReturnResult是自定义对象时,Mock返回null值,但当它是基元类型bool时,它会按预期工作,c#,unit-testing,mocking,.net-core,moq,C#,Unit Testing,Mocking,.net Core,Moq,我正在使用.NETCore(1.1)中的Moq,并且花了一点时间来理解这种行为,因为interweb上的所有示例都表明了这样做应该不会有任何问题 我已经尝试过: 返回(Task.FromResult(…) 返回(Task.FromResult(…) ReturnsAsync(…) 模拟IHttpClient接口以包装PostAsync、PutAsync和GetAsync。所有这些都返回一个ApiResponse对象 var mockClient = new Mock<IHttpClie
- 返回(Task.FromResult(…)
- 返回(Task.FromResult(…)
- ReturnsAsync(…)
IHttpClien
t接口以包装PostAsync
、PutAsync
和GetAsync
。所有这些都返回一个ApiResponse
对象
var mockClient = new Mock<IHttpClient>();
后同步定义:
mockClient.Setup(x => x.PostAsync(url, JsonConvert.SerializeObject(body), null))
.Returns(Task.FromResult(new ApiResponse()));
public async Task<ApiResponse> PostAsync(string url, string body, string authToken = null)
mockClient.Setup(x => x.PostAsync(url, JsonConvert.SerializeObject(body), null))
.Returns(Task.FromResult(bool));
public async Task<bool> PostAsync(string url, string body, string authToken = null)
后同步定义:
mockClient.Setup(x => x.PostAsync(url, JsonConvert.SerializeObject(body), null))
.Returns(Task.FromResult(new ApiResponse()));
public async Task<ApiResponse> PostAsync(string url, string body, string authToken = null)
mockClient.Setup(x => x.PostAsync(url, JsonConvert.SerializeObject(body), null))
.Returns(Task.FromResult(bool));
public async Task<bool> PostAsync(string url, string body, string authToken = null)
更新
[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);
}
逻辑同步:
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;
}
}
public异步任务LoginAsync(字符串用户,字符串密码)
{
var body=new{Username=user,Password=Password};
尝试
{
var response=wait_http.PostAsync(_login_url,JsonConvert.SerializeObject(body),null);
返回响应。状态==1;
}
捕获(例外情况除外)
{
记录器错误(ex);
返回false;
}
}
邮政同步:
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
};
}
公共异步任务PostAsync(字符串url、字符串正文、字符串authToken=null)
{
var client=新的HttpClient();
var content=newstringcontent(body,Encoding.UTF8,“application/json”);
var response=wait client.PostAsync(新的Uri(url)、内容);
var resp=wait response.Result.Content.ReadAsStringAsync();
返回新的ApiResponse
{
内容=响应,
StatusCode=response.Result.StatusCode,
原因=response.Result.ReasonPhrase
};
}
基于上面提供的最小示例,假设一个简单的测试方法
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;
}
}
}
公共类API服务{
专用IHttpClient_http;
私有字符串\u登录\u url;
公共API服务(IHttpClient httpClient){
这个。_http=httpClient;
}
公共异步任务LoginAsync(字符串用户、字符串密码){
var body=new{Username=user,Password=Password};
试一试{
var response=wait_http.PostAsync(_login_url,JsonConvert.SerializeObject(body),null);
返回response.StatusCode==HttpStatusCode.OK;
}捕获(例外情况除外){
//记录器错误(ex);
返回false;
}
}
}
正确配置后,以下测试工作正常
[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);
}
[事实]
公共异步任务登录\u应该\u返回\u True(){//x.PostAsync(It.IsAny(),It.IsAny(),null))
.ReturnsAsync(新的ApiResponse(){StatusCode=HttpStatusCode.OK});
var api=新的api服务(mockClient.Object);
//表演
var response=await api.LoginAsync(“,”);
//断言
Assert.IsTrue(响应);
}
上述内容仅用于演示目的,仅表明只要测试配置正确并基于预期行为执行,它就可以工作
花点时间查看一下,以便更好地理解如何使用该框架。同意。据我所知,关键的区别似乎在于我推断的参数类型与您的“正确”设置之间的设置。我想假设真的会让人感到恶心。不过我很想深入了解我使用的“不正确”设置的原因。非常感谢!@Walaitki moq直接响应您配置的期望值。虽然我的示例非常简单,但您需要设置moq以期望您要测试的行为。如果您不提供mock期望的行为,那么它将无法按预期执行。要确切说明您的配置不起作用的原因,请参阅que中的详细信息stion。拼图中遗漏了太多的部分。可能像这样简单的东西和字符串中的空格放错了地方。
It.IsAny
是一个相当危险的演示示例,你知道:)@VMAtm怎么会这样?根据测试的性质,有时您并不关心依赖关系。您只需要确保它们不会导致可能会妨碍测试执行的错误。请记住,这些类型的单元测试是要单独进行的。:)该代码的主要问题是很容易复制并粘贴到真正应该关心参数的测试中。对我来说,在这种情况下,最好设置一对user/password
,并根据它们的值进行设置。