Klasa EntityMetadata i testy jednostkowe

Jako dinozaur piszący ręcznie kod uruchamiany na platformie Power Apps („Low-code, you fool!”) stworzyłem sobie dziś klasę repozytorium, umożliwiającą pobieranie metadanych tabel Microsoft Dataverse. Rozwiązanie wydawało mi się być banalnym w swojej prostocie:

public interface IMetadataRepository
{
    EntityMetadata GetEntityMedatada(string entityName);
    void Initialize(IOrganizationService service); 
}

public class MetadataRepository : IMetadataRepository
{
    protected IOrganizationService OrganizationService;
    
    public void Initialize(IOrganizationService service)
    {
        OrganizationService = service;
    }

    public EntityMetadata GetEntityMedatada(string entityName)
    {
        var retrieveEntityRequest = new RetrieveEntityRequest
        {
            EntityFilters = EntityFilters.All,
            LogicalName = entityName
        };

        var response = (RetrieveEntityResponse)OrganizationService.Execute(retrieveEntityRequest);
        return response.EntityMetadata;
    }
}

Powyższe repozytorium wykorzystywałem do dynamicznego pobierania informacji nt. podstawowego atrybutu encji oraz dynamicznego ustawiania jego wartości. Wyglądało to mniej-więcej w następujący sposób:

var entityMetadata = _metadataRepository.GetEntityMedatada(entityName);

var entity = new Entity(entityName);
entity.Attributes.Add(entityMetadata.PrimaryNameAttribute, entityPrimaryAttributeValue); 
var entityId = _repository.Create(entity);

Problem pojawił się w momencie próby stworzenia testu jednostkowego dla ww. kodu. Okazało się niestety, że wykorzystywana przeze mnie właściwość klasy EntityMetadata jest tylko do odczytu. Próba utworzenia własnego obiektu ww. typu i poustawiania jego atrybutów wewnątrz testu jednostkowego zakończyła się niepowodzeniem. Na szczęścia ratunkiem okazał się mechanizm refleksji, który do spółki z frameworkiem Moq pozwolił utworzyć „zaślepkę” przedstawionego na początku repozytorium.

Mock<IMetadataRepository> metadataRepository = new Mock<IMetadataRepository>();
metadataRepository.Setup(m => m.GetEntityMedatada(It.IsAny<string>())).Returns(() => {
    var metadata = new EntityMetadata();
    typeof(EntityMetadata)
        .GetProperty("PrimaryNameAttribute")
        .SetValue(metadata, "pg_name");
    return metadata;
});

Nie chcę w tym miejscu wchodzić w dyskusję na temat tego, czy wykorzystania refleksji wewnątrz testów jednostkowych jest dobrą praktyką i czy problem, na który napotkałem nie wynika z błędów w architekturze. Zdaję sobie również sprawę, że powyższą zaślepkę dałoby się pewnie zastąpić dedykowaną strukturą wrapperów. Po rozważeniu alternatyw stwierdziłem jednak, że dla mojego przypadku przytoczone powyżej rozwiązanie jest „good enough” 😉.

Wykorzystujcie więc na własną odpowiedzialność.

Total Views: 129 ,
Be the first to comment

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *