I am new to unit testing and I've been facing this error that I can't even understand what it means.
So I have a solution called HotelApp, working perfectly with no issues. Now I am trying to unit test it. I am trying to test my Data access. I used Dapper for my data access and xUnit, Moq and Autofac for my testing.
**below is the data access class and interface. **
public class SqlDataAccess : ISqlDataAccess
{
private readonly IConfiguration _config;
public SqlDataAccess(IConfiguration config)
{
_config = config;
}
public List<T> LoadData<T, U>(string sqlStatement,
U parameter,
string connectionStringName,
bool isStoredProcedure = false)
{
string? connectionString = _config.GetConnectionString(connectionStringName);
CommandType commandType = CommandType.Text;
if (isStoredProcedure == true)
{
commandType = CommandType.StoredProcedure;
}
using (IDbConnection connection = new SqlConnection(connectionString))
{
List<T> rows = connection.Query<T>(sqlStatement, parameter, commandType: commandType).ToList();
return rows;
}
}
}
public interface ISqlDataAccess
{
List<T> LoadData<T, U>(string sqlStatement, U parameter, string connectionStringName, bool isStoredProcedure = false);
}
**below is the data access methode and interface. **
public class SqlData : IDatabaseData
{
private readonly ISqlDataAccess _db;
private const string connectionStringName = "SqlDb";
public SqlData(ISqlDataAccess db)
{
_db = db;
}
public RoomTypesModel GetRoomTypesDetailById(int roomTypeId)
{
RoomTypesModel model= new RoomTypesModel();
model = _db.LoadData<RoomTypesModel, dynamic>("[dbo].[spRoomTypeDetails_GetById]",
new { RoomTypeId = roomTypeId },
connectionStringName,
true).First();
return model;
}
}
**below is my unit test code. **
public class SqlDataTests : MockData
{
private static DateTime pStartDate = DateTime.Now;
private DateTime pEndDate = pStartDate.AddDays(1);
private const string connectionStringName = "SqlDb";
[Fact]
public void GetRoomTypesDetailById_ShouldReturnRoomDetails()
{
var roomTypeId = 2;
var returnedRoom = GetAvailableRoomTypes()[1] ;
var sqlStatment = "[dbo].[spRoomTypeDetails_GetById]";
List<RoomTypesModel> roomList = new List<RoomTypesModel>();
roomList.Add(returnedRoom);
using (var mock = AutoMock.GetLoose())
{
mock.Mock<ISqlDataAccess>()
.Setup(x => x.LoadData<RoomTypesModel, dynamic>(sqlStatment, roomTypeId, connectionStringName, true))
.Returns(roomList);
var _dbMock = mock.Create<SqlData>();
// Arrange
var expected = returnedRoom;
//Act
var actual = _dbMock.GetRoomTypesDetailById(roomTypeId);
// Assurt
Assert.NotNull(actual);
Assert.Equal(actual, expected);
}
}
}
**below is my MockData clase code. **
public class MockData
{
public List<RoomTypesModel> GetRoomTypesDetailById(int roomId)
{
List<RoomTypesModel> RoomDetails = new()
{
new RoomTypesModel { Id = 1, Title = "King Size Bed", Description = "A room with a king size bed and a window view.", Price = 100 },
new RoomTypesModel { Id = 2, Title = "Two Queen Size Ben", Description = "A room with two queen size bed", Price = 115 },
new RoomTypesModel { Id = 3, Title = "Execlusive Suite", Description = "Two room, each with one king size bed and a window view", Price = 205 }
};
return RoomDetails.Where(room => room.Id == roomId).ToList();
}
}
This is a photo of my project to better understand it
Now I am expecting (actual) to retun an object with Id = 2 and the test to pass since I have no errors in the project and when I build. But when I run the test in debudding mode I keep getting the below error when It reaches the act part
var actual = _dbMock.GetRoomTypesDetailById(roomTypeId);
Error Detials:
System.Reflection.TargetInvocationException
HResult=0x80131604
Message=Exception has been thrown by the target of an invocation.
Source=System.Private.CoreLib
StackTrace:
at System.RuntimeMethodHandle.InvokeMethod(Object target, Span`1& arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) in /_/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.cs:line 435
at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters) in /_/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodBase.cs:line 53
at Xunit.Sdk.TestInvoker`1.CallTestMethod(Object testClassInstance) in /_/src/xunit.execution/Sdk/Frameworks/Runners/TestInvoker.cs:line 150
at Xunit.Sdk.TestInvoker`1.<>c__DisplayClass48_0.<<InvokeTestMethodAsync>b__1>d.MoveNext() in /_/src/xunit.execution/Sdk/Frameworks/Runners/TestInvoker.cs:line 257
at Xunit.Sdk.ExecutionTimer.<AggregateAsync>d__4.MoveNext() in /_/src/xunit.execution/Sdk/Frameworks/ExecutionTimer.cs:line 48
at Xunit.Sdk.ExceptionAggregator.<RunAsync>d__9.MoveNext() in /_/src/xunit.core/Sdk/ExceptionAggregator.cs:line 90
This exception was originally thrown at this call stack:
System.Linq.ThrowHelper.ThrowArgumentNullException(System.Linq.ExceptionArgument)
System.Linq.Enumerable.TryGetFirst<TSource>(System.Collections.Generic.IEnumerable<TSource>, out bool)
System.Linq.Enumerable.First<TSource>(System.Collections.Generic.IEnumerable<TSource>)
HotalAppLibrary.Data.SqlData.GetRoomTypesDetailById(int) in SqlData.cs
HotelAppLibrary.Tests.SqlDataTests.GetRoomTypesDetailById_ShouldReturnRoomDetails() in SqlDataTests.cs
Inner Exception 1:
ArgumentNullException: Value cannot be null. (Parameter 'source')