25
Views
6
Comments
Solved
[Testing Framework] Certain usage pattern causes MockAction to stop working
Question
testing-framework
Reactive icon
Forge asset by Leonardo Fernandes
Application Type
Reactive

Hi Leonardo,


Nice to meet you, and thank you for your great work on the Testing Framework.


I've encountered an issue where the MockAction feature stops working under certain conditions.

Let me describe the situation below.


Assumption:

The Consumer (named TF_SUT) consumes the ProducerAction from a Producer module (named TF_SUT_Producer).


Steps to reproduce:

1. Run a test that includes a MockAction whose TargetAction is ActionRef("TF_SUT_Producer", "ProducerAction")


2. Then run a test that  includes a MockAction whose TargetAction is ActionRef("TF_SUT", "ProducerAction")


In this case, the second test (step 2) fails because the mock is not applied.

The issue persists until the IIS process is recycled.

Alternatively, republishing the TestSuite also resolves the issue.


Interestingly, if you run step 2 before step 1 (e.g., run the tests in the order 2. → 1. → 2.),

the mock is applied correctly and there is no failure.


Could this be a bug in the Testing Framework?


Kind regards,


Yukinao


TF_SUT.oml
TF_Forum_TestSuite.oml
TF_SUT_Producer.oml
2019-07-08 11-04-35
Leonardo Fernandes
 
MVP
Solution

Hi yukinao.

It looks like the ActionRef("TF_SUT", "ProducerAction") is returning an action that simply invokes the producer. That action actually doesn't exist in the module, but turns out that OutSystems generates a .NET method with the same as an action would (if it existed).

Since that .NET method is so simple (it simply invokes the producer action), its calls get automatically inlined by .NET when it's first executed. That means that any code that is invoking ProducerAction from TF_SUT (which, again, is simply a synthetic action generated by OutSytems), will be changed to invoke the ProducerAction from TF_SUT_Producer directly (in reality, it invokes an intermediate proxy, called a reference proxy, but that detail doesn't matter for this analysis).


So in the first scenario that the Producer test is executed first, it has a chance to invoke the synthetic action and it gets inlined. When the Consumer test is executed, the mock is created but the mocked action is never invoked (because it has been inlined already).

In the second scenario, the Consumer test is executed first, which mocks the action before it has any chance to be inlined, and thus the mock works.


In summary, in both cases you should be mocking the action using ActionRef("TF_SUT_Producer", "ProducerAction"), since the module that owns the action is TF_SUT_Producer. The fact that ActionRef("TF_SUT", "ProducerAction") worked sometimes was a coincidence, and it will stop working in future versions of Testing Framework.


Regarding your question about mocking GenerateGuid, it's not possible yet, but I will work on making that available.

UserImage.jpg
yukinao iwamoto

Hi Leonardo,

Thank you so much for your quick and detailed response!

Your explanation about the synthetic action and inlining behavior makes perfect sense, and I really appreciate the clarity.

I’ll make sure to follow your recommended approach going forward.


Thanks as well for considering support for mocking GenerateGuid.

I'm looking forward to being able to mock it in the future.


Really appreciate your support! 


Kind regards,

Yukinao 

UserImage.jpg
yukinao iwamoto

Hi Leonardo,


I hope you've been doing well!


I'm following up after a couple of months with a quick additional question regarding the Testing Framework.


When mocking internal database CRUD actions such as GetEntity (the ones automatically generated by OutSystems), I've noticed that specifying the producer module for the ActionRef doesn't seem to apply the mock as expected.

However, when I specified the consumer module instead, the mock worked correctly.


In this case, is it acceptable to specify the consumer module in the ActionRef instead, in order to get the mock to work?


Thanks again for your previous insights—they were incredibly helpful!


Kind regards,

Yukinao

2019-07-08 11-04-35
Leonardo Fernandes
 
MVP


Hi Yukinao. You're correct, each module that consumes an entity has its own entity actions, instead of referencing the producer actions. I don't know why it is done this way for entity actions. So you should mock the entity actions using the consumer module name, and that will work.

Having said that, typically the CRUD actions are in the same module that produces the entity, and the entity is exposed as read-only, so there are no consumers of the entity actions (unless you're mocking the Get action).

UserImage.jpg
yukinao iwamoto


Hi Leonardo,

Thank you again for the detailed explanation!


From what I understand, this behavior might depend on how OutSystems handles things internally, so it could potentially change in the future.

That said, I'll make use of the consumer module name mocking approach for now, with that possibility in mind.


Thanks again for your continued support, really appreciate it!


Kind regards,

Yukinao

UserImage.jpg
yukinao iwamoto

Following up on my previous message, I've encountered a similar issue related to mocking the "GenerateGuid" action provided by the System module.


Although the exact conditions are still unclear, the mock targets the action via the consumer module rather than the prodducer, so I suspect this could be a similar case.

Specifically, the call looks like this: ActionRef("TF_SUT", "GenerateGuid")


The issue does not always occur, In fact, the mock often works correctly, so the reproducibility is low.


Is there a better or recommended way to reference "GenerateGuid" in this context?

I've tried using "ActionRef("(System)", "GenerateGuid")" but that did not work.


Kind regards.

2019-07-08 11-04-35
Leonardo Fernandes
 
MVP
Solution

Hi yukinao.

It looks like the ActionRef("TF_SUT", "ProducerAction") is returning an action that simply invokes the producer. That action actually doesn't exist in the module, but turns out that OutSystems generates a .NET method with the same as an action would (if it existed).

Since that .NET method is so simple (it simply invokes the producer action), its calls get automatically inlined by .NET when it's first executed. That means that any code that is invoking ProducerAction from TF_SUT (which, again, is simply a synthetic action generated by OutSytems), will be changed to invoke the ProducerAction from TF_SUT_Producer directly (in reality, it invokes an intermediate proxy, called a reference proxy, but that detail doesn't matter for this analysis).


So in the first scenario that the Producer test is executed first, it has a chance to invoke the synthetic action and it gets inlined. When the Consumer test is executed, the mock is created but the mocked action is never invoked (because it has been inlined already).

In the second scenario, the Consumer test is executed first, which mocks the action before it has any chance to be inlined, and thus the mock works.


In summary, in both cases you should be mocking the action using ActionRef("TF_SUT_Producer", "ProducerAction"), since the module that owns the action is TF_SUT_Producer. The fact that ActionRef("TF_SUT", "ProducerAction") worked sometimes was a coincidence, and it will stop working in future versions of Testing Framework.


Regarding your question about mocking GenerateGuid, it's not possible yet, but I will work on making that available.

UserImage.jpg
yukinao iwamoto

Hi Leonardo,

Thank you so much for your quick and detailed response!

Your explanation about the synthetic action and inlining behavior makes perfect sense, and I really appreciate the clarity.

I’ll make sure to follow your recommended approach going forward.


Thanks as well for considering support for mocking GenerateGuid.

I'm looking forward to being able to mock it in the future.


Really appreciate your support! 


Kind regards,

Yukinao 

UserImage.jpg
yukinao iwamoto

Hi Leonardo,


I hope you've been doing well!


I'm following up after a couple of months with a quick additional question regarding the Testing Framework.


When mocking internal database CRUD actions such as GetEntity (the ones automatically generated by OutSystems), I've noticed that specifying the producer module for the ActionRef doesn't seem to apply the mock as expected.

However, when I specified the consumer module instead, the mock worked correctly.


In this case, is it acceptable to specify the consumer module in the ActionRef instead, in order to get the mock to work?


Thanks again for your previous insights—they were incredibly helpful!


Kind regards,

Yukinao

2019-07-08 11-04-35
Leonardo Fernandes
 
MVP


Hi Yukinao. You're correct, each module that consumes an entity has its own entity actions, instead of referencing the producer actions. I don't know why it is done this way for entity actions. So you should mock the entity actions using the consumer module name, and that will work.

Having said that, typically the CRUD actions are in the same module that produces the entity, and the entity is exposed as read-only, so there are no consumers of the entity actions (unless you're mocking the Get action).

UserImage.jpg
yukinao iwamoto


Hi Leonardo,

Thank you again for the detailed explanation!


From what I understand, this behavior might depend on how OutSystems handles things internally, so it could potentially change in the future.

That said, I'll make use of the consumer module name mocking approach for now, with that possibility in mind.


Thanks again for your continued support, really appreciate it!


Kind regards,

Yukinao

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