从存储库模拟返回Null

时间:2019-02-14 15:42:16

标签: c# moq

我是Mocking的新手,不确定我是否做对了。我试图使用使用WriteNameToDatabase方法的函数GetName,所以我的类设置如下:

我的员工界面:

public interface IEmployee
{
    Task<string> GetName();
   string WriteNameToDataBase();

}

我的员工班级

 public class Employee : IEmployee
    {
        public Task<string> GetName()
        {
            throw new NotImplementedException();
        }

        public string WriteNameToDataBase()
        {
            var employeeName = GetName();

            return $"Wrote {employeeName.Result} to database";

        }

我的单元测试班

 [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);

    }

这总是返回我Was Expecting 'Wrote Frank to database,但实际上为空`,或者是Assert给我的某种含义。我在做什么错了?

谢谢

编辑:更正为使用ReturnsAsync("Frank");

2 个答案:

答案 0 :(得分:4)

几个问题,一个是您没有等待异步呼叫:

apply

两次嘲笑结果错误,moq支持异步:

    public async Task<string> WriteNameToDataBase()
    {
        var employeeName = await GetName();

        return $"Wrote {employeeName} to database";

    }

但是这里的主要问题是您模拟整个对象。这没有测试任何东西。您可能想要更多类似的东西:

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";

    }
 }

然后您的测试如下:

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

答案 1 :(得分:1)

请注意,您是基于接口IEmployee而不是类Employee创建Mock对象,因此根本就没有测试Employee类,因此您无法期望Employee类中要运行的任何代码。

您需要考虑一下您的测试实际上试图做什么,以及什么构成项目中的“单元”。

您可以创建一个包含INameGetter方法的新接口GetName(或对您的项目有意义的名称)。然后,您可以将此新接口作为雇员类中的依赖项,并在测试中对其进行模拟。像这样:

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您还需要研究异步/等待以使用返回Task的方法。编辑:我现在在这里修复了它,但实际上您不想使用Task.Result