How do I get arguments passed to a data access layer that uses System.Action as an input parameter?

StackOverflow https://stackoverflow.com/questions/14128927

  •  12-01-2022
  •  | 
  •  

Question

I'm trying to create some unit tests for an application I've recently inherited. Currently using NSubstitute because that's what the previous programmer used, but I'm not attached to it.

The method I'm testing calls the DataService class' Create method.

Calling Create Method

var contactProductLink = this.dsService.Create<ContactProductLink>(x =>
{
    x.ContactRoleId = prod.RoleId;
    x.ContactId = contactViewModel.ContactId;
    x.ProductId = prod.ProductId;
    x.Active = true;
    x.InsertDate = DateTime.Now;
    x.InsertUserId = user.employeeId;
    x.UpdateDate = DateTime.Now;
    x.UpdateUserId = user.employeeId;
});

DataService Create Method:

public TEntity Create<TEntity>(Action<TEntity> propertySetter = null) where TEntity : class
{
    var tEntity = this.Context.Create<TEntity>();
    if (propertySetter != null)
    {
        propertySetter(tEntity);
    }

    return tEntity;
}

The approach I've taken (and maybe there's a better way) is to use NSubstitute to mock the DataService. When I'm doing my assertions at the end, I'm checking to make sure that the Create method was called:

mockDataSupplierService.Received().Create<ContactProductLink>(Arg.Any<Action<ContactProductLink>>());

However, I'd like to also verify the input that was sent to the method is correct, and here's where I'm running into trouble. I can get the System.Action object that was passed to the Create method, but I can't figure out how to pull out the parameters (such as ContactRoleId, ContactId, etc. as posted in the calling create method code snippet).

So after all of that what I'm asking is:

  1. How can I access those input parameters so I can verify the correct arguments are being passed to the data service? Is it even possible?
  2. Is there a better way to do this than what I'm currently trying to do?

Solution

//Arrange
mockDataSupplierService.Create<ContactProductLink>(Arg.Do<Action<ContactProductLink>>(x=> actionToPopulateEntity = x));

//Assert
mockDataSupplierService.Received().Create<ContactProductLink>(Arg.Any<Action<ContactProductLink>>());
var entity = new ContactProductLink();
actionToPopulateEntity.Invoke(entity);
Assert.AreEqual(ExpectedContactId, entity.ContactId);
Was it helpful?

Solution

How can I access those input parameters so I can verify the correct arguments are being passed to the data service? Is it even possible?

Essentially you can't, as it is not possible to extract "code" details from action (consider what happens when you pass an action that doesn't set any properties - this is totally legal, but would break hypothetical mechanism).

However, you can try this instead:

  1. Create entity with initial values
  2. Use Arg.Invoke argument, telling NSubstitute to use chosen object as action parameter
  3. Verify that entity properties values changed

For example:

// Arrange
var entity = new ContactProductLink
{
    ContactRoleId = // ...
    // ...
};

mockDataSupplierService
    .Create<ContactProductLink>(Arg<ContactProductLink>.Invoke(entity));

// Act
// ...

Assert.That(entity.ContactRoleId, Is.EqualTo(2));
// ...
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top