I'm not able to detect throw in Xunit testing in .net, my test is terminating at throw?

68 Views Asked by At

Hey I have made a Appointment Application using .net core, The thing is I removed to the default api controller middleware to produce custom error schema when ever an error occurs. to detect the error and override the default error produced by .net I throw an exception (custom HttpResponseException) and modify the exception at IActionfilter after executing. Now I'm not able to write the unit test test for the part of code where I'm throwing the error. The test stops executing with the following error refer image below. can anyone please help ??

I tried

  • try catch in the unit test (I have commented that part you can see)

  • I tied Assert.Throws technique but my code never reaches the point

  • I also tried to run my application using dotnet run where the debugger is off to avoid detecting the throw and halting it, and then I tried to run my test which also failed

git hub link to the repo if you want to understand the project : github link

the error image is : The error when test is executed

This is my buisness layer code for which the test is written, It is written for createAppointment :

using AppointmentApi.DataAccess;
using AppointmentApi.Models;
using AppointmentApi.validators;

namespace AppointmentApi.Buisness
{
  public class AppointmentBL : IAppointmentBL
  {
    private readonly IAppointmentDL _appointmentDL;

    public AppointmentBL(IAppointmentDL appointmentDL)
    {
      _appointmentDL = appointmentDL;
    }
    public List<Appointment> GetAppointments(AppointmentDateRequest appointmentDateRequest)
    {
      appointmentDateRequest.Validate<AppointmentDateRequest, AppointmentDateRequestValidator>();
      return _appointmentDL.GetAppointments(date: appointmentDateRequest.Date);

    }
    public Guid CreateAppointment(AppointmentRequest appointmentrequest)
    {
      appointmentrequest.Validate<AppointmentRequest, AppointmentRequestValidator>();

      DateOnly dateOnly = new DateOnly(appointmentrequest.StartTime.Year, appointmentrequest.StartTime.Month, appointmentrequest.StartTime.Day);
      var appointments = _appointmentDL.GetAppointments(null, dateOnly);

      var conflictingAppointment = appointments?.FirstOrDefault(item =>
       (item.StartTime < appointmentrequest.StartTime && item.EndTime > appointmentrequest.StartTime) ||
       (appointmentrequest.EndTime > item.StartTime && appointmentrequest.EndTime < item.StartTime));

      if (conflictingAppointment != null)
      {

        var errorString = (conflictingAppointment.StartTime < appointmentrequest.StartTime ?
                           appointmentrequest.StartTime : appointmentrequest.EndTime) +
                          "is conflicting with an existing appointment having startTime:" +
                         $"{conflictingAppointment.StartTime} and endTime: {conflictingAppointment.EndTime}";        
            throw new HttpResponseException(StatusCodes.Status409Conflict, new CustomError { Message = errorString });
      }

      return _appointmentDL.CreateAppointment(appointmentrequest);
    }
    public void DeleteAppointment(Guid id)
    {
      var result = _appointmentDL.GetAppointments(id, null);
      if (result.Count == 0)
      {
          throw new HttpResponseException(StatusCodes.Status404NotFound, new CustomError(){Message="Appointment not found"}); 
      }
      _appointmentDL.DeleteAppointment(id);
    }
  }
}

The unit test code which is failing :

        [Fact]
        public void TestCreateAppointment_Throws_conflictError()
        {
            var mockAppointmentDL = new Mock<IAppointmentDL>();
            var appointmentBL = new AppointmentBL(mockAppointmentDL.Object);
            var appointmentRequest2 = new AppointmentRequest
            {
                Title = "New Test Appointment",
                StartTime = DateTime.Parse("2023/10/3 10:20"),
                EndTime = DateTime.Parse("2023/10/3 11:00")
            };
            var appointmentRequest1 = new AppointmentRequest
            {
                Title = "New Test Appointment",
                StartTime = DateTime.Parse("2023/10/3 09:00"),
                EndTime = DateTime.Parse("2023/10/3 10:20")
            };
            var appointments = new List<Appointment>
            {
                new Appointment { Title = "Go To Gym", StartTime = DateTime.Parse("2023/10/3 
                10:00"), EndTime = DateTime.Parse("2023/10/3 11:00") }
            };
            DateOnly dateOnly = new DateOnly(appointmentRequest2.StartTime.Year, 
            appointmentRequest2.StartTime.Month, appointmentRequest2.StartTime.Day);
            mockAppointmentDL.Setup(x => x.GetAppointments(null, dateOnly)).Returns(appointments);
            var expectedGuid = Guid.NewGuid();
            mockAppointmentDL.Setup(x => 
            x.CreateAppointment(appointmentRequest2)).Returns(expectedGuid);
            var errorDto = new CustomError() { Message = "Appoinment conflict" };
            // Act
            var result = appointmentBL.CreateAppointment(appointmentRequest2);
            var result2 = appointmentBL.CreateAppointment(appointmentRequest1);

            // Assert
            var exception = Assert.Throws<HttpResponseException>(() => 
            appointmentBL.CreateAppointment(appointmentRequest2));
            Assert.Equal(409, exception.Status);

            //failed
            // try
            // {
            //     appointmentBL.CreateAppointment(appointmentRequest2);
            // }
            // catch (HttpResponseException exception)
            // {
            //     Assert.Equal(StatusCodes.Status409Conflict, exception.Status);
            // }

            //failed
            // var exception = Record.Exception(() =>
            // appointmentBL.CreateAppointment(appointmentRequest2));
            // Assert.NotNull(exception);
            // Assert.IsType<HttpResponseException>(exception);
            // var httpResponseException = (HttpResponseException)exception;
            // Assert.Equal(409, httpResponseException.Status);
        }

1

There are 1 best solutions below

2
Tenatus On BEST ANSWER

mockAppointmentDL is setup to return an appointment that conflicts with both of the CreateAppointment calls in the //Act section of the unit test.

The //Act section should be deleted if you want the test to pass (all the appointmentBL.CreateAppointment calls should be in Assert.Throws lambdas)