2013 Sep 16 12:16 PM
Hi,
I understand that we can subclass /BOBF/CL_TOOL_TEST_DOUBLE_SM and /BOBF/CL_TOOL_TEST_DOUBLE_INT to mock the service manager etc. and override the corresponding calls.
Since the base classes do not have any implementation, we would have to implement all RETRIEVEs, CREATEs etc. specifically.
I thought that it would be helpful to have kind of a generic double which already is able to work on internal buffers and just abstracts the database access, e.g. by pulling its data out of the test data container. It is possible to write such thing with internal tables, but not absolutely easy, especially when it comes to "before images", "alternative keys", "queries" etc.
I found class /BOBF/CL_TOOL_AUNIT_DAC_TDC which seems to be similar to what I want, but I think it is from the old unit testing framework.
Could we use this to replace the DAC and to keep the rest standard?
Is there anything else you recommend how to achieve this with as few effort as possible?
Basically the requirement is:
Create a unit test as easy as possible, which reads its data from a TDC and where the data can be checked (and asserted) after the CUT has been executed.
Best Regards,
Bruno
2013 Sep 17 4:35 PM
Dear Bruno,
quite funny you ask for mocking using a test data container. The "old" BOPF unit-test-framework was based on that, but there were some limitations. Particularly cross-BO-write-access was not possible.
In discussions, we often argued what is actually the "unit" to be tested: When mocking the DAC and using the service manager to evoke the part of business logic to test, the unit is quite huge: There are e. g. after-loading-determinations running, potentially even determination dependencies are taken care of, validations are executed and so on. However, when thinking of all that as the "unit" (unit := "one atomic interaction of the user with the application"), mocking the database access imho is the best way to do it - and BOPF already provides an implementation of the DAC-interface which reads from a TDC and writes into a buffer.
In our project, we do have a representation of the testdata container which allows us to create a mock. We only use the current image as of now:
This could be perfectly used if only it was possible to inject the DAC-instance at test-runtime.
Unfortunately, the capabilities of injecting a DAC-mock via the test manager are quite limited: Only a static class can be registered for a particular BO node (assume the type SEOCLSNAME 😞
So the only thing which came to our mind is to use a static class which act as a broker for the DAC-instances.
Mocking is done during the CLASS-SETUP of the UT:
Inside the "mock-manager" (mockable DAC), the instances are buffered and the mock is propagated to the test-manager which delegates to them internally:
This way, we can use the old-functionality by BOPF to extract manually created process data to a TDC and to use it for automated tests.
Not perfect, but it works.
Could I make the approach clear?
Cheers,
Oliver
2013 Sep 17 4:35 PM
Dear Bruno,
quite funny you ask for mocking using a test data container. The "old" BOPF unit-test-framework was based on that, but there were some limitations. Particularly cross-BO-write-access was not possible.
In discussions, we often argued what is actually the "unit" to be tested: When mocking the DAC and using the service manager to evoke the part of business logic to test, the unit is quite huge: There are e. g. after-loading-determinations running, potentially even determination dependencies are taken care of, validations are executed and so on. However, when thinking of all that as the "unit" (unit := "one atomic interaction of the user with the application"), mocking the database access imho is the best way to do it - and BOPF already provides an implementation of the DAC-interface which reads from a TDC and writes into a buffer.
In our project, we do have a representation of the testdata container which allows us to create a mock. We only use the current image as of now:
This could be perfectly used if only it was possible to inject the DAC-instance at test-runtime.
Unfortunately, the capabilities of injecting a DAC-mock via the test manager are quite limited: Only a static class can be registered for a particular BO node (assume the type SEOCLSNAME 😞
So the only thing which came to our mind is to use a static class which act as a broker for the DAC-instances.
Mocking is done during the CLASS-SETUP of the UT:
Inside the "mock-manager" (mockable DAC), the instances are buffered and the mock is propagated to the test-manager which delegates to them internally:
This way, we can use the old-functionality by BOPF to extract manually created process data to a TDC and to use it for automated tests.
Not perfect, but it works.
Could I make the approach clear?
Cheers,
Oliver
2013 Sep 17 4:46 PM
Hi Oliver,
this looks exactly how I would have approached it with the technical possibilities that are given. Great to hear that this works, it could be very helpful 🙂 I need to try it.
It should also be possible with /BOBF/CL_TOOL_AUNIT_FRW=>PREPARE_MOCK to create a TDC connected mock for the internal access. In this way we could test the smaller "units" (e.g. only one determination).
On the other hand I see also determination dependencies as useful in unit tests (maybe they should be called integration tests than), since a lot of our issues comes from them.
Regards,
Bruno
Message was edited by: Bruno Haller
2013 Sep 18 5:30 AM
Dear Bruno,
On the other hand I see also determination dependencies as useful in unit tests (maybe they should be called integration tests than), since a lot of our issues comes from them.
fully agreed! In our daily language, we differentiate between those "scenario-unit-tests" which are an atomic interaction from the user's perspective and "BOPF Unit-Tests" where we use only the TDC-based old framework by BOPF which tests elementary entities (validations, determinations).
Please let us know your findings when implementing tests, it's a topic often underestimated
Cheers,
Oliver
2013 Nov 08 11:30 AM
Dear Bruno,
Basically mockA can create fake and mock objects quite easily.
https://github.com/uweku/mockA
But honestly I don't know if you can convince BOPF to take over lifetime control of these mocked instances.
mockA allows you only to control method output based an input patterns, carry out verifications against mock object method calls and lets you also define raisable exceptions.
But you need to be in charge of the instance lifetimes, which could not be the case if you use BOPF.
Regards,
Uwe
2014 Feb 24 9:19 AM
Hi Oliver,
it has been a while now, since our discussion, but finally I found some time to implement your suggestion and it works perfectly.
I did a quick try with a generic query, a retrieve, retrieve_by_assocation and converting an alternative key. All returned the expected result from the TDC.
I do not have a real-life test yet, but it looks promising.
Thanks again and Best Regards,
Bruno
2024 Jul 04 6:13 PM - edited 2024 Jul 04 6:19 PM
Hi everyone. I am also trying to create unit tests for our BO using /BOBF/CL_TOOL_TEST_DOUBLE_SM however when I create a child class inherited from /BOBF/CL_TOOL_TEST_DOUBLE_SM the class is compiled but unit test doesn't run. I have a following warning message:
Syntax errors in program [/BOBF/CL_TOOL_TEST_DOUBLE_SM==CP] prevent analysis of test classes in program [ZTEST_BOBF_TD]
at the same time class /BOBF/CL_TOOL_TEST_DOUBLE_SM gives no syntax errors.
I also noticed that in the table TAUNIT_PROG_INFO this class has BAD_RESSOURCE /BOBF/CL_TOOL_TEST_DOUBLE_SM==CP value. I have no clue what it means too.
Did someone faced thing like this.
Here is a simple code which doesn't work in our system:
REPORT ZTEST_BOBF_TD.
class ltc_main definition for testing risk level harmless duration short.
private section.
methods td for testing.
endclass.
class ltc_td definition inheriting from /BOBF/CL_TOOL_TEST_DOUBLE_SM for testing.
endclass.
class ltc_main implementation.
method td.
new ltc_td( ).
endmethod.
endclass.
I have also noticed that if I copy /BOBF/CL_TOOL_TEST_DOUBLE_SM to a new class like ZCL_TOOL_TEST_DOUBLE_SM one to one without any modifications, then using this new class in own scripts works very well.
Does someone have ideas why?
Thanks!