Loading device in teststand for embedded device only at top-level, but has to be imported at lower level also to work

Hello,

I am currrently trying to get a teststand (system tests for an embedded device) going with the following premise in mind:

I have multiple suites to group tests and they are organized hierachically…

  • Base-Testand > folder with init.robot
    • Suite #1 > folder with init.robot
    • Suite #2 > folder with init.robot
    • Suite #3 > folder with init.robot
      • Suite #31 > folder with init.robot
        • Testfile #311 > file with a test suite (mostly containing one testcase)

Any test running from any level , for example #311 needs certain devices (power supplies, etc.) and those devices shall only be present (imported) once across the complete execution with a specific name (there can be multiple devices of the same type, each with an individual name and individual parameters for things like COM-port, etc…)…
I achieve such representation of multiple devices of the same type (und therefore the same library) as follows:

  • Library devtype1/devtype1.py port=COM20 baudrate=${9600} AS devtype1_instanceA
  • Library devtype1/devtype1.py port=COM20 baudrate=${9600} AS devtype1_instanceB
    The library devtype1/devtype1.py contains a single class with “ROBOT_LIBRARY_SCOPE = ‘GLOBAL’” in the class (acc. Robot Framework User Guide)…

The init.robot in folder “Base-Testand” uses a resource file, which performs these “library instanciations” as well as provides keywords for setup and teardown, which are called directly in that init.robot file (on level Base-Teststand).

so far, so good…

Now, for these instances to be available, either during development in VSCode as well as at runtime for just calling keywords from “devtype1_instanceA” oder “devtype1_instanceB”, I additionally need to load the resource file within the test file as I have already done in the init.robot at Base-Testand level.
This is what does not make sense currently for me, since those “instances” named “devtype1_instanceA” and “devtype1_instanceB” have scope=global set by the python lib…

Why is this second load of the resource file in the lower-level testfile necessary when the library is set to scope=global…?

Thanks !

Cheers
Niels Göran

===
P.S.:

I checked if this import of the two instances is actually running correctly…
It appears as this mostly the case… with some interesting observations…
it also works as expected…
Somehow the SCOPE and VERSION assignments are interpreted as keywords even in the BuiltIn lib… this happens at the first import (following are from cache, and do not show this message)

00:31:21.207 In library ‘BuiltIn’: Adding keyword ‘ROBOT_LIBRARY_SCOPE’ failed: Not a method or function.
00:31:21.208 In library ‘BuiltIn’: Adding keyword ‘ROBOT_LIBRARY_VERSION’ failed: Not a method or function.

At the end of this import, the BuiltIn lib seems to imported correctly, and got assigned the scope== GLOBAL

00:31:21.233 Imported library ‘BuiltIn’ with arguments [ - ] (version 7.2, class type, GLOBAL scope, 107 keywords).

Furthermore, the first suite below “Base-Teststand”, named “Suite #1”, the Builtin lib is imported again, but this time from cache…

00:31:21.238 Found library ‘BuiltIn’ with arguments [ - ] from cache.

On the level, where I load the resource file (which in turn imports the library with a specific name), the library is loaded correctly as GLOBAL (but also showing the issue with “SCOPE and VERSION assignments being interpreted as keywords”):

00:31:21.244 Imported resource file ‘base-testStand.resource’ (4 keywords).
00:31:21.254 Imported library class ‘example’ from ‘example.py’.
00:31:21.269 Imported library ‘example.py’ with arguments [ port=COM20 | baudrate=9600 ] (version 0.1.0, class type, GLOBAL scope, 10 keywords).
00:31:21.269 Imported library ‘example.py’ with name ‘devtype1_instanceA’.

Still makes sense to me, since the library was imported with specific values for the constructor (as specified and scope global…
Not sure, why the name only shows up in the second line…

Within the debug messages for the test file “Testfile #311” itself, I found:

00:48:04.878 Found resource file ‘base-testStand.resource’ from cache.
00:48:04.881 Imported library class ‘example’ from ‘example.py’.
00:48:04.883 Found library ‘example.py’ with arguments [ port=COM20 | baudrate=9600 ] from cache
00:48:04.884 Imported library ‘example.py’ with name ‘devtype1_instanceA’.

Only difference being the “from cache”…

Not sure if this is the answer that you are looking for, but the official documentation does state that:

Initialization files have the same structure and syntax as test case files, except that they cannot have test case sections and not all settings are supported. Variables and keywords created or imported in initialization files are not available in the lower level test suites. If you need to share variables or keywords, you can put them into resource files that can be imported both by initialization and test case files.

So even though you imported keywords in the initialisation file, they do not get imported automatically to the actual tests suites.

The solution could be to add a resource file for each of your folders and import that resource file in initialisation and tests suite files?

1 Like

Hej hej,

thanks for pointing me exactly where I needed to look…
No idea, why I did’nt fint it in the first place and no idea, why I wasn’t able to phrase my question in a short form straight to the point…

One remaining questions for me though:

Does this also mean that the instance is not available until it is imported on the corresponding level as well? Despite the library being imported as GLOBAL…?
(Then it would be the case, that RF tries to import it again on that level, but sees an identical object with scope GLOBAL, and therefore the already existing instance is used instead…)
Or would it be possible to simply import the keywords and utilize them with the existing instance (scope=GLOBAL) ?

Thanks !

Cheers
Niels Göran

1 Like

Pleasure,
Regarding the different libraries scope, the relevant information is here.

It boils down to, class librairies are instanciated:

  • for each test if they have the TEST scope (ie. the class internal data is not preserved between tests)
  • for each suite if they have the SUITE scope (ie. the class internal data is shared among the tests of the same suite [file or folder, I am not sure])
  • only once for the whole robot execution if they have the GLOBAL scope

With the exception:

If a library is imported multiple times with different arguments, a new instance is created every time regardless the scope.

I am not sure what is best for your case. GLOBAL seems close enough.

Hej hej,

thanks for the repsonse…
I think I got the scope of the library correctly…

What threw me off, was that, despite the library being instantiated with scope GLOBAL in a higher-level suite, I would expect the instance to be available in the lower-level suite for use with keywords…
Given that those keywords need to be imported on the lower-level anyway, I get that the instance is also not available until the import happened…
Just from a programmer point-of-view, I was expecting the objects to be available in lower-level suites / tests…

Thanks !

Cheers
Niels Göran

1 Like