2

I have the following class and the interface

public interface IService
{
    Task<double> GetAccDetails(int personId);
}

public class Person
{
    private int _personId;
    private IService _service;

    public Person(int personId, IService service)
    {
        _personId= personId;
        _service = service;
    }

    public double Amount {get; set;}

    public async void UpdateBanckingAcc()
    {
        Amount = await _service.GetAccDetails(_personId);
    }
}

I am trying to write nunit test for it:

[Test]
public async void Test1([Values(200)]int personId)
{
    const double expectedResult = 20;    
    var serviceMock = new Mock<IAccountService>();

    //Here I tried both options:
    //serviceMock.Setup(s =>  s.GetAccDetails(It.Is<int>(id => id == personId)))
    //    .ReturnsAsync(() => expectedResult);
    //And:
    serviceMock.Setup(s=>  s.GetAccDetails(It.Is<int>(id => id == personId)))
    .Returns(() => Task.FromResult<double>(personId));

    var person = new Person(personId, serviceMock.Object);

    person.UpdateBanckingAcc();

    double res = person.Amount;
    Assert.AreEqual(expectedResult, res);
}

And the test fails. For some strange reason I can not debug it.
So the issue I see here is the call :

person.UpdateBanckingAcc();

it should be

await person.UpdateBanckingAcc();

but it does not like if I use await keyword.

Please advise.

Also one more question: is there something specific in terms of nunit testing for async methods I should test, like task status testing, etc?

VMAtm
  • 27,943
  • 17
  • 79
  • 125
J.Doe
  • 143
  • 1
  • 2
  • 5
  • What version of NUnit are you using? Recent versions should indicate that an async void test is invalid. – Charlie Dec 20 '16 at 18:48

2 Answers2

0

The problem here is that your method UpdateBankingAcc has return type void which should be returning a Task<T> or Task, so you need to change the signatures of it to reutrn a Task like:

public async Task UpdateBanckingAcc()
{
    Amount = await _service.GetAccDetails(_personId);
}

and now you would need to change your test code to be:

await person.UpdateBanckingAcc();

double res = person.Amount;
Assert.AreEqual(expectedResult, res);

you should never return void from an async method, unless it is UI controls events, you can read about the best practices of using async and await at following :

https://msdn.microsoft.com/en-us/magazine/jj991977.aspx

http://www.tonicodes.net/blog/why-you-should-almost-never-write-void-asynchronous-methods/

async/await - when to return a Task vs void?

Community
  • 1
  • 1
Ehsan Sajjad
  • 61,834
  • 16
  • 105
  • 160
0

There is a simple rule: async void is used for fire-and-forget behavior and only for this. If you need async method, change it's return type to the Task, as @EhsanSajjad said. This corresponds to the unit tests too:

public async Task UpdateBanckingAcc()

public async Task Test1([Values(200)]int personId)
VMAtm
  • 27,943
  • 17
  • 79
  • 125