2

I am tring to test one web api method in asp.net core 2.

Web api

method:

public IActionResult Delete(int id)
{
    try
    {
        var success = sportsService.DeleteSport(id);

        if (!success)
        {
            return new NotFoundResult();
        }
        return new OkResult();
    }
    catch (Exception e)
    {
        return new StatusCodeResult(400);
    }
}

Unit testing part:

private Mock<ISportsService> mockService;

[SetUp]
public void Setup()
{
    mockService.SetupSequence(x => x.DeleteSport(It.IsAny<int>())).
        Returns(true). // OkResult();
        Returns(false). // NotFoundResult()
        Throws(new Exception()); //Exception
}

Test method looks like this. What I am not clear about with this method is, what the right approach to testing the method is?

[Test]
public void TestStrategyControllerWithDelete()
{
    var result = controller.Delete(STRAT_ID);
    var okResult = result as ObjectResult;
    Assert.AreEqual(HttpStatusCode.NotFound, okResult.StatusCode);
    Assert.AreEqual(HttpStatusCode.OK, okResult.StatusCode);
    Assert.AreEqual(400, okResult.StatusCode);
}

and i am okresult as null ! and not able to get okResult.StatusCode

3 Answers 3

2

You are setting up your mock to:

  • return true when it is first called
  • return false when it is called 2nd time.
  • throw new Exception() when it is called again.

However, in your test you are only calling it once (var result = controller.Delete(STRAT_ID); so your Moq will always return true.

Write 3 separate tests, rather than one:

[Test]
public void Delete_ReturnsOkResult_IfDeleteSuccess()
{
  const int deleteId = 1234;
  mockService.Setup(x => x.DeleteSport(deleteId)).Returns(true);

  var result = controller.Delete(deleteId);

  Assert.IsInstanceOf<OkResult>(result);
}

Unit tests should be independant. They should be able to be run in any order without interfering with one another. However, by configuring a SetupSequence() in the [SetUp] step you are tying at least 3 of them together and forcing an order to them.

Edit: for "and not able to get okResult.StatusCode"* update to question

You are returning an OKResult, NotFoundResult and StatusCodeResult. None of these inherit from ObjectResult which is why it is NULL. I've updated my code sample to check for explicit type (OKResult), this will need updated for each test case.

If you want to check individual StatusCodes you could case it to a StatusCodeResult as all return types can be cast to this.

Sign up to request clarification or add additional context in comments.

5 Comments

alright, so what should i write in [SetUp] public void Setup()? if we're already doing mockService.Setup(x => x.DeleteSport(deleteId)).Returns(true); inside!!, [setup] and [Test]
if anyone can explain all three cases ( ok, not found, exception) with example then it will be great. thanks
@Var the 3 cases will be very similar to the single one that is shown. You'll need to change the mockService.Setup() step and the assertion as those are what changes between each test.
can you please explain " asserts" for Exception? - Assert.IsInstanceOf(typeof(StatusCodeResult), result);? is correct? - i would love to check 400 status return or not
For returning the 400/BadRequest I think the following should work: Assert.AreEqual(400, (result as StatusCodeResult).StatusCode);. Alternatively you could return BadRequestResult and test for IsInstanceOf<BadRequestResult> to keep it consistent with the other return types.
1

You can do something like this,

1) Success:

[Test]
public void Delete_ReturnsOkResult_IfDeleteSuccess()
{
  bool isSucceed = true;
  const int deleteId = 1234;

  this.MockSportService(isSucceed);

  var result = controller.Delete(deleteId);

  var okResult = result as ObjectResult;    
  Assert.AreEqual(HttpStatusCode.OK, okResult.StatusCode);
}

2) Failure:

[Test]
public void Delete_ReturnsNotFound_IfIdNotFound()
{
  bool isSucceed = false;
  const int deleteId = 1234;

  this.MockSportService(isSucceed);

  var result = controller.Delete(deleteId);

// Do proper asserts
}

3) Exceptions,

[Test]
public void Delete_ThrowsException_IfIdNotFound()
{
  bool isSucceed = false;
  const int deleteId = 1234;

   mockService.Setup(x => x.DeleteSport(It.IsAny<int>())).
        Throws(new Exception());

  // Act
  var result = controller.Delete(deleteId);

  // Assert
  Assert.True(result is StatusCodeResult); // Asserting that the return type is StatusCodeResult

  // Casting the result as StatusCodeResult object
  var statusCodeResult = result as StatusCodeResult;

  // Asserting the status code
  Assert.AreEqual(400, statusCodeResult.StatusCode);
}

And have the common method for mocking for success and failure,

private void MockSportService(bool isSucceed)
{
mockService.Setup(x => x.DeleteSport(deleteId)).Returns(isSucceed);
}

3 Comments

Thanks, how about the bold text in my question any clue?
can you please explain " asserts" for Exception?
@Var - Edited the asserts for an exception. I hope this helps.
0

You'll need to call controler.Delete(...) method 3 times to have the moq return the different status/exception.

I would suggest having discreet tests for each returned status - one for each status (true/false) and one for the exception.

1 Comment

See @Fermin answer above - he nailed it

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.