845614720
845614720

Reputation: 838

Mocking From Repository Returns Null

I'm new to Mocking and not sure if I'm doing this correctly. I'm trying to use the function WriteNameToDatabase which uses the GetName method so I have my classes setup like so:

My Employee Interface:

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

}

My Employee Class

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

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

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

        }

My Unit Test 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);

    }

This always returns me Was Expecting 'Wrote Frank to database but was actually null` or something to that effect that Assert gives me. What am I doing wrong?

Thank you

Edit: Corrected to use ReturnsAsync("Frank");

Upvotes: 0

Views: 2058

Answers (2)

Liam
Liam

Reputation: 29750

Several problems, one your not awaiting your async call:

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

        return $"Wrote {employeeName} to database";

    }

two your mocking the result wrong, moq supports async:

mockObject.Setup(x => x.GetName()).ReturnsAsync("Frank");

But the big issue here is your mocking the entire object. This isn't testing anything. You probably want something more like:

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

    }
 }

Your repo is now a separate thing represented by this interface

public interface INameRepo
{
      Task<string> GetName();
}

Then your test looks like:

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

}

If you just want to verify that GetName is called you should be using Verify instead of returning an arbitrary value:

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

}

Upvotes: 4

Slappywag
Slappywag

Reputation: 1223

Note that you're creating a Mock object based on the interface IEmployee not the Class Employee, so you're not testing your Employee class at all, therefore you cannot expect any code in the Employee class to be run.

You need to think about what your test is actually trying to do, and what constitutes a "unit" in your project.

You could create a new interface INameGetter (or something with a name that makes sense to your project) which contains the GetName method. You could then take this new interface as a dependency in your employee class and mock it out in your test. Something like:

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

And your test method

[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 You alse need to look into async/await for using methods returning Task. Edit: I've now fixed it here, but essentially you don't want to be using Task.Result.

Upvotes: 1

Related Questions