6
Views
1
Comments
[Testing Framework] "Operation is not valid" error when mocking a site property from a library
testing-framework
Reactive icon
Forge asset by Leonardo Fernandes
Application Type
Reactive

There seems to be a bug when using the MockSiteProperty actions targeting a site property from a module of Library type.


Operation is not valid due to the current state of the object.

   at OutSystems.HubEdition.RuntimePlatform.SitePropertiesInfo.set_Item(ObjectKey name, Object value)
   at OutSystems.NssTestingServerSideInstrumentation.CodeInstrumentation.Instrumentation.MockSiteProperty(String module, String siteProperty, Object value)
   at ssTestingFramework.RssExtensionTestingServerSideInstrumentation.MssInstrumentMockSiteProperty(HeContext heContext, String inParamModuleName, String inParamSitePropertyName, Object inParamSitePropertyValue)


I've attached modules that reproduce the issue, using Testing Framework v6.0.0.


SitePropertyMockError_Lib.oml
TestSuite_SitePropertyMockError.oml
2019-10-27 01-32-56
Caio Santana Magalhães
 
MVP

I managed to fix it by sprinkling some magic in the TestingServerSideInstrumentation XIF, as described below.

I've run 500+ test cases after these changes (some of which do site properties mocking), and they all continue to work.

I'd rather have this patched up in the original Forge component so as not to have a customized version of Testing Framework installed in my environment. Let me know if I can help with this.


TestExecutionContext.cs:

Add the following member to the Execution class:

public IDictionary<ObjectKey, SiteProperty> MockedSiteProperties = new Dictionary<ObjectKey, SiteProperty>();


Instrumentation.cs:

Add this static method to the Instrumentation class:

private static bool Prefix_LibraryTryGetValueByKey(ObjectKey __0, ref SiteProperty __1, ref bool __result) {
    if (!IsExecutingTest) {
        return true;
    }

    if (TestExecutionContext.Instance.Get().MockedSiteProperties.TryGetValue(__0, out SiteProperty mocked)) {
        __1 = mocked;
        __result = true;
        return false;
    }

    return true;
}

Add this Harmony patch to InitializeMockInstrumentation():

// Mock library site property reads (InConfigsSitePropertiesCollection doesn't cache)
MethodInfo libraryTryGetValueByKey = typeof(InConfigsSitePropertiesCollection).GetMethod(nameof(InConfigsSitePropertiesCollection.TryGetValueByKey), BindingFlags.Public | BindingFlags.Instance);
MethodInfo prefixLibraryTryGetValueByKey = mock.GetMethod(nameof(Prefix_LibraryTryGetValueByKey), BindingFlags.NonPublic | BindingFlags.Static);
harmony.Patch(libraryTryGetValueByKey, prefix: new HarmonyMethod(prefixLibraryTryGetValueByKey));

Lastly, modify MockSiteProperty() with the following at the end of the try {} block:

if (siteProperties is AppSettingsSitePropertiesInfo) {
    // Library: set_Item is not overridden (throws) and InConfigsSitePropertiesCollection doesn't cache;
    // register a SiteProperty snapshot for the Harmony prefix to return on subsequent reads.
    ISitePropertiesCollection collection = siteProperties.GetSitePropertiesCollection();
    if (!collection.TryGetValueByKey(sitePropertyKey, out SiteProperty sitePropertyEntry)) {
        throw new SitePropertyNotFoundException(module, siteProperty, $"site property {siteProperty} not present in runtime collection");
    }
    sitePropertyEntry.ChangeValue(TypeCastStrategy.Cast(value, new SiteProperties().GetRuntimeType(module, siteProperty)));
    TestExecutionContext.Instance.Get().MockedSiteProperties[sitePropertyKey] = sitePropertyEntry;
} else {
    siteProperties[sitePropertyKey] = TypeCastStrategy.Cast(value, new SiteProperties().GetRuntimeType(module, siteProperty));
}

Screenshots of changes:

  • TestExecutionContext.cs:

  • Instrumentation.cs:


Community GuidelinesBe kind and respectful, give credit to the original source of content, and search for duplicates before posting.