Reputation: 838
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
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
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