从存储库中模拟 Returns Null
Mocking From Repository Returns Null
我是 Mocking 的新手,不确定我是否做对了。我正在尝试使用函数 WriteNameToDatabase
,它使用 GetName
方法,所以我的 类 设置如下:
我的员工界面:
public interface IEmployee
{
Task<string> GetName();
string WriteNameToDataBase();
}
我的员工Class
public class Employee : IEmployee
{
public Task<string> GetName()
{
throw new NotImplementedException();
}
public string WriteNameToDataBase()
{
var employeeName = GetName();
return $"Wrote {employeeName.Result} to database";
}
我的单元测试Class
[Test]
public void WriteToDBShouldWrite()
{
var mockObject = new Mock<IEmployee>();
mockObject.Setup(x => x.GetName()).ReturnsAsync("Frank");
string result = mockObject.Object.WriteNameToDataBase();
Assert.AreEqual("Wrote Frank to database", result);
}
这总是 returns 我 Was Expecting 'Wrote Frank to database
但实际上是 null` 或 Assert 给我的那种效果。我做错了什么?
谢谢
编辑:更正为使用 ReturnsAsync("Frank");
几个问题,一个是你没有等待你的异步调用:
public async Task<string> WriteNameToDataBase()
{
var employeeName = await GetName();
return $"Wrote {employeeName} to database";
}
两个你的mocking结果不对,moq支持async:
mockObject.Setup(x => x.GetName()).ReturnsAsync("Frank");
但是这里的大问题是你模拟了整个对象。这不是在测试任何东西。您可能想要更像:
public class Employee : IEmployee
{
private readonly INameRepo _repo;
public Employee(INameRepo repo)
{
//this is dependancy injection
_repo = repo;
}
public async Task<string> WriteNameToDataBase()
{
var employeeName = await _repo.GetName();
return $"Wrote {employeeName.Result} to database";
}
}
你的 repo 现在是这个接口所代表的一个独立的东西
public interface INameRepo
{
Task<string> GetName();
}
然后你的测试看起来像:
[Test]
//note this is also async now
public async Task WriteToDBShouldWrite()
{
//mock the dependencies
var mockObject = new Mock<INameRepo>();
mockObject.Setup(x => x.GetName()).ReturnsAsync("Frank");
//test the actual object
Employee emp = new Employee(mockObject.Object);
string result = await emp.WriteToDBShouldWrite();
Assert.AreEqual("Wrote Frank to database", result);
}
如果您只想验证 GetName
是否被调用,您应该使用 Verify
而不是返回任意值:
[Test]
//note this is also async now
public async Task WriteToDBShouldWrite()
{
var mockObject = new Mock<INameRepo>();
mockObject.Setup(x => x.GetName()).ReturnsAsync("Frank");
string result = mockObject.Object.WriteNameToDataBase();
Employee emp = new Employee(mockObject.Object);
await emp.WriteToDBShouldWrite();
//ensure GetName is called once and once only
mockObject.Verify(v => v.GetName(), TimesOnce);
}
请注意,您是基于接口 IEmployee
而不是 Class Employee
创建 Mock 对象,因此您不是在测试 Employee
class,因此您不能指望 Employee
class 中的任何代码是 运行.
您需要考虑您的测试实际上要做什么,以及什么构成了您项目中的 "unit"。
您可以创建一个包含 GetName
方法的新接口 INameGetter
(或名称对您的项目有意义的名称)。然后,您可以将这个新接口作为您的员工 class 的依赖项,并在您的测试中对其进行模拟。类似于:
public interface IEmployee
{
Task<string> WriteNameToDataBase();
}
public interface INameGetter
{
Task<string> GetName();
}
public class Employee : IEmployee
{
private INameGetter nameGetter;
public Employee(INameGetter n)
{
nameGetter = n;
}
public Task<string> WriteNameToDataBase()
{
var employeeName = await nameGetter.GetName();
return $"Wrote {employeeName} to database";
}
}
还有你的测试方法
[Test]
public void WriteToDBShouldWrite()
{
var mockObject = new Mock<INameGetter>();
mockObject.Setup(x => x.GetName()).Returns(Task.FromResult("Frank"));
string result = new Employee(mockObject.Object).WriteNameToDataBase();
Assert.AreEqual("Wrote Frank to database", result);
}
N.B 您还需要研究 async/await 以了解使用返回 Task
的方法。编辑:我现在在这里修复了它,但基本上你不想使用 Task.Result
.
我是 Mocking 的新手,不确定我是否做对了。我正在尝试使用函数 WriteNameToDatabase
,它使用 GetName
方法,所以我的 类 设置如下:
我的员工界面:
public interface IEmployee
{
Task<string> GetName();
string WriteNameToDataBase();
}
我的员工Class
public class Employee : IEmployee
{
public Task<string> GetName()
{
throw new NotImplementedException();
}
public string WriteNameToDataBase()
{
var employeeName = GetName();
return $"Wrote {employeeName.Result} to database";
}
我的单元测试Class
[Test]
public void WriteToDBShouldWrite()
{
var mockObject = new Mock<IEmployee>();
mockObject.Setup(x => x.GetName()).ReturnsAsync("Frank");
string result = mockObject.Object.WriteNameToDataBase();
Assert.AreEqual("Wrote Frank to database", result);
}
这总是 returns 我 Was Expecting 'Wrote Frank to database
但实际上是 null` 或 Assert 给我的那种效果。我做错了什么?
谢谢
编辑:更正为使用 ReturnsAsync("Frank");
几个问题,一个是你没有等待你的异步调用:
public async Task<string> WriteNameToDataBase()
{
var employeeName = await GetName();
return $"Wrote {employeeName} to database";
}
两个你的mocking结果不对,moq支持async:
mockObject.Setup(x => x.GetName()).ReturnsAsync("Frank");
但是这里的大问题是你模拟了整个对象。这不是在测试任何东西。您可能想要更像:
public class Employee : IEmployee
{
private readonly INameRepo _repo;
public Employee(INameRepo repo)
{
//this is dependancy injection
_repo = repo;
}
public async Task<string> WriteNameToDataBase()
{
var employeeName = await _repo.GetName();
return $"Wrote {employeeName.Result} to database";
}
}
你的 repo 现在是这个接口所代表的一个独立的东西
public interface INameRepo
{
Task<string> GetName();
}
然后你的测试看起来像:
[Test]
//note this is also async now
public async Task WriteToDBShouldWrite()
{
//mock the dependencies
var mockObject = new Mock<INameRepo>();
mockObject.Setup(x => x.GetName()).ReturnsAsync("Frank");
//test the actual object
Employee emp = new Employee(mockObject.Object);
string result = await emp.WriteToDBShouldWrite();
Assert.AreEqual("Wrote Frank to database", result);
}
如果您只想验证 GetName
是否被调用,您应该使用 Verify
而不是返回任意值:
[Test]
//note this is also async now
public async Task WriteToDBShouldWrite()
{
var mockObject = new Mock<INameRepo>();
mockObject.Setup(x => x.GetName()).ReturnsAsync("Frank");
string result = mockObject.Object.WriteNameToDataBase();
Employee emp = new Employee(mockObject.Object);
await emp.WriteToDBShouldWrite();
//ensure GetName is called once and once only
mockObject.Verify(v => v.GetName(), TimesOnce);
}
请注意,您是基于接口 IEmployee
而不是 Class Employee
创建 Mock 对象,因此您不是在测试 Employee
class,因此您不能指望 Employee
class 中的任何代码是 运行.
您需要考虑您的测试实际上要做什么,以及什么构成了您项目中的 "unit"。
您可以创建一个包含 GetName
方法的新接口 INameGetter
(或名称对您的项目有意义的名称)。然后,您可以将这个新接口作为您的员工 class 的依赖项,并在您的测试中对其进行模拟。类似于:
public interface IEmployee
{
Task<string> WriteNameToDataBase();
}
public interface INameGetter
{
Task<string> GetName();
}
public class Employee : IEmployee
{
private INameGetter nameGetter;
public Employee(INameGetter n)
{
nameGetter = n;
}
public Task<string> WriteNameToDataBase()
{
var employeeName = await nameGetter.GetName();
return $"Wrote {employeeName} to database";
}
}
还有你的测试方法
[Test]
public void WriteToDBShouldWrite()
{
var mockObject = new Mock<INameGetter>();
mockObject.Setup(x => x.GetName()).Returns(Task.FromResult("Frank"));
string result = new Employee(mockObject.Object).WriteNameToDataBase();
Assert.AreEqual("Wrote Frank to database", result);
}
N.B 您还需要研究 async/await 以了解使用返回 Task
的方法。编辑:我现在在这里修复了它,但基本上你不想使用 Task.Result
.