wapt49
wapt49

Reputation: 233

How to eliminate the dependency on the database from a unit test

Is it possible to create a unit test for this method?

public void CheckIndicatorMeasurementRecordingValidity(IndicatorMeasurementRecording indicatorMeasurementRecording)
{
   var isDateRangeOverLapping = this.db.IndicatorMeasurementRecordingRepository.Any(r => r.IndicatorId == indicatorMeasurementRecording.Indicator.Id && r.Id != indicatorMeasurementRecording.Id
                && r.RecordingDateRange.ToDateTime >= indicatorMeasurementRecording.RecordingDateRange.FromDateTime
                && r.RecordingDateRange.FromDateTime <= indicatorMeasurementRecording.RecordingDateRange.ToDateTime);

   if (isDateRangeOverLapping)
   {
       throw new GrcUserException(IndicatorThresholdValidityManagementLocal.DateRangeOverlapping);
   }
}

I tried to create the test like this

[TestMethod]
public void Indicator_measurement_date_range_overlapping_shall_throw_exception()
{
    var indicator = new Indicator();
    var oldIndicatorMeasurementRecording = new IndicatorMeasurementRecording();
    var newIndicatorMeasurementRecording = new IndicatorMeasurementRecording();
    var errorMessage = string.Empty;

    oldIndicatorMeasurementRecording.Id = 1;
    oldIndicatorMeasurementRecording.RecordingDateRange.FromDateTime = DateTime.Today.AddDays(-5);
    oldIndicatorMeasurementRecording.RecordingDateRange.ToDateTime = DateTime.Today;
    indicator.IndicatorMeasurementRecordings.Add(oldIndicatorMeasurementRecording);

    oldIndicatorMeasurementRecording.Id = 2;
    newIndicatorMeasurementRecording.RecordingDateRange.FromDateTime = DateTime.Today.AddDays(-2);
    newIndicatorMeasurementRecording.RecordingDateRange.ToDateTime = DateTime.Today;
    newIndicatorMeasurementRecording.Indicator = indicator;

    try
    {
        this.indicatorValidityProxy.CheckIndicatorMeasurementRecordingValidity(newIndicatorMeasurementRecording);
    }
    catch (Exception ex)
    {
        errorMessage = ex.Message;
    }

    Assert.AreEqual(IndicatorThresholdValidityManagementLocal.DateRangeOverlapping, errorMessage);
}

The problem is, the test always fails because this.db.IndicatorMeasurementRecordingRepository.Count for test is always 0. For development purpose it always returns the correct number. Only in the test purpose is it 0.

Can anyone tell me why this.db.IndicatorMeasurementRecordingRepository.Count for test purpose is always 0? And what is the best practice for writing the test for my case?

Upvotes: 0

Views: 404

Answers (1)

NikolaiDante
NikolaiDante

Reputation: 18639

I'm not sure what the.db is, but assuming public class MyContext : DbContext and this.db is of type MyContext then with Mock you can:

var contextMock = new Mock<MyContext>();
// arrange more

Essentially you would configure the contextMock to return a known set of your objects (IndicatorMeasurementRecording?) when the IndicatorMeasurementRecordingRepository is queried. Something like:

var dbSetMock = new Mock<IDbSet<DbEntity>>();
dbSetMock.Setup(m => m.Provider).Returns(data.Provider);
dbSetMock.Setup(m => m.Expression).Returns(data.Expression);
dbSetMock.Setup(m => m.ElementType).Returns(data.ElementType);
dbSetMock.Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());

var contextMock = new Mock<MyContext>();
contextMock 
    .Setup(x => x.DbEntities)
    .Returns(dbSetMock.Object);

Where data would be a list of your objects to be returned from the mock.

Some links / examples to help you:

I can't recreate your test case as there is too much code not there, but if you provide a mcve I am more than happy to look at the test in more detail.

Upvotes: 2

Related Questions