How to mock SecurityToken with Moq?

Hi,

How would i go about mocking a SecurityToken for unit tests where I don’t extend LitiumApplicationTestBase, hence have no IoC?

If it had an interface all would have been good to go.

If Mocking is not possible, how would I go about doing “new SecurityToken” without IoC? Perhaps mocking it’s inparameters?

I have used code below, has dependencies on IoC still but perhaps it is a start that you can work with.

protected SecurityToken GetMockToken(Guid organizationId, string roleId = null, bool anonymous = false)
{
    var roleSystemId = roleId == null ? Guid.Empty : IoC.Resolve<RoleService>().Get(roleId).SystemId;
    var personService = IoC.Resolve<PersonService>() as MockPersonService;
    personService.SetMockPersonRoles(organizationId, new List<Guid> {roleSystemId});
    var userId = anonymous ? Guid.Empty : personService.MockPerson.SystemId;

    var identity = new ClaimsIdentity(new List<Claim>
    {
        new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", userId.ToString())
    }, "MockAuthenticationType");
    return new SecurityToken(identity);
}
/// <summary>
///     Registering a custom PersonService in IoC is Required
///     since SecurityToken internally does a resolve on PersonService to get person
/// </summary>
public class MockPersonService : PersonService
{
    public Person MockPerson;

    public MockPersonService()
    {
        MockPerson = new Person(Guid.NewGuid())
        {
            SystemId = Guid.NewGuid(),
            Id = "MockPersonId",
            OrganizationLinks = new List<PersonToOrganizationLink>()
        };
    }

    public void SetMockPersonRoles(Guid organizationSystemId, List<Guid> roleIds)
    {
        MockPerson.OrganizationLinks.Clear();

        if (organizationSystemId != Guid.Empty)
            MockPerson.OrganizationLinks.Add(new PersonToOrganizationLink(organizationSystemId)
            {
                RoleSystemIds = new HashSet<Guid>(roleIds ?? new List<Guid>())
            });
    }

    public override void Create([NotNull] Person person)
    {
        throw new NotImplementedException();
    }

    public override void Delete([NotNull] Person person)
    {
        throw new NotImplementedException();
    }

    public override Person Get(Guid systemId)
    {
        if (systemId.Equals(MockPerson.SystemId))
            return MockPerson;

        throw new Exception($"PersonId '{systemId}' does not equal mock person id '{MockPerson.SystemId}'");
    }

    public override Person Get([NotNull] string id)
    {
        throw new NotImplementedException();
    }

    public override IEnumerable<Person> Get([NotNull] IEnumerable<Guid> systemIds)
    {
        throw new NotImplementedException();
    }

    public override void Update([NotNull] Person person)
    {
        throw new NotImplementedException();
    }

    public override IEnumerable<Person> GetByOrganization(Guid organizationSystemId)
    {
        throw new NotImplementedException();
    }
}

Thanks! Good idea making a mockable helper service.

But I found another way!

Instead of injecting SecurityContext to my service under test - I used another, mockable, service I already had injected: ModuleECommerce and used it’s _moduleECommerce.AdminToken where I needed a token.

Looks like mocking ModuleECommerce ran into some troubles internally too, so then I will implement the solution you suggested @marten .

1 Like

This is what I ended up implementing to avoid the internal use of IoC in ModuleECommerce and the SecuryToken.

[Service(ServiceType = typeof(OrderUtilities), Lifetime = DependencyLifetime.Singleton)]
public abstract class OrderUtilities
{
public abstract Order GetOrder(string orderAlias);
public abstract OrderCarrier GetOrderCarrier(string orderAlias);
public abstract DeliveryMethodCarrier GetDeliveryMethodCarrier(Guid deliveryMethodID);
public abstract void SetDeliveryStatus(Delivery delivery, short status);
public abstract void AddOrUpdateAdditionalOrderInfo(Order order, string key, string value);
public abstract Country GetCountry(OrderCarrier litiumOrderCarrier);
}

Lot’s of extra code just because ModuleECommerce wasn’t abstract/had interfaces and made funny stuff (IoC lookups) inside the constructor.

internal class OrderUtilitiesImpl : OrderUtilities
{
    private readonly ModuleECommerce _moduleECommerce;
    private readonly ChannelService _channelService;

    public OrderUtilitiesImpl(ModuleECommerce moduleECommerce, ChannelService channelService)
    {
        _moduleECommerce = moduleECommerce;
        _channelService = channelService;
    }

    public override Order GetOrder(string orderAlias)
    {
        return _moduleECommerce.Orders.GetOrder(orderAlias, _moduleECommerce.AdminToken);

    }

    public override OrderCarrier GetOrderCarrier(string orderAlias)
    {
        return _moduleECommerce.Orders.GetOrder(orderAlias, _moduleECommerce.AdminToken)
                    .GetAsCarrier(true, true, true, true, true, true);
    }

    public override DeliveryMethodCarrier GetDeliveryMethodCarrier(Guid deliveryMethodID)
    {
        return _moduleECommerce.DeliveryMethods.Get(deliveryMethodID, _moduleECommerce.AdminToken)
                    .GetAsCarrier();
    }

    public override void SetDeliveryStatus(Delivery delivery, short status)
    {
        delivery.SetDeliveryStatus(status, _moduleECommerce.AdminToken);
    }

    public override void AddOrUpdateAdditionalOrderInfo(Order order, string key, string value)
    {
        order.AddOrUpdateAdditionalOrderInfo(key, value, _moduleECommerce.AdminToken);
    }

    public override Country GetCountry(OrderCarrier litiumOrderCarrier)
    {
        var channel = _channelService.Get(litiumOrderCarrier.ChannelID);
        var countryId = litiumOrderCarrier?.CountryID;
        if (countryId == null || countryId == Guid.Empty)
        {
            countryId = channel.CountryLinks.FirstOrDefault()?.CountrySystemId;
        }
        var country = countryId.MapTo<Country>();
        return country;
    }

}

I also use a wrapper class for the ECommerce-module in code that need to be testable. This was an issue with all areas (PIM/Media/CMS/Customers) earlier, but since version 5 Litium has become easier to test and with Litium 8 the new more testable Service-architecture will be implemented in ECommerce also.

2 Likes

with Litium 8 the new more testable Service-architecture will be implemented in ECommerce also

Yay! :slight_smile:

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.