1
votes

I am trying to write a test for the messaging functionality of a website. In this test I use a keyword which should iterate thourgh a list of users, locate the chat window for each user, then import a custom library written in Python which holds the pass/fail logic of the test. The custom library should take as arguments the type of subscriptions of the message sender, the subscription type of the user receiving the message and the initial sent message.

The test case looks like this:

*** Settings ***
Variables   ../resources/usersToMessage.py
Variables  ../resources/messageSenders.py
Resource  ../chatTests/chatTests.resource

*** Test Cases ***

DemoTest
    [Documentation]     send messages to other users
    [tags]  demo
    [Template]  Log in as user and send messages
    FOR     ${user}     IN      @{messageSenders}
            ${user}
    END



*** Keywords ***
Log in as user and send messages
    [Arguments]     ${testcase}
    Send Messages

Send Messages
    ${randomString}=   generate string
    Set Global Variable  ${SENT_MESSAGE}  ${randomString}
    ${arguments}=      Create List     LogMany      conversationBox    ${randomString}
    Locate Conversations  ${arguments}       @{usersToMessage}


Locate Conversations
    [Arguments]   ${arguments}   @{users}
    FOR     ${user}     IN   @{users}
        Log Many      ${user}   @{arguments}
        Log     ${user}[username]
        Import Library     Services.ChatTestCase  BASIC  ${user}[subscription]    ${SENT_MESSAGE}
        ${expected_chat_message}=   expected chat message
        Log Many    the current user subscription is ${user}[subscription]  the expected chat message is ${expected_chat_message}
        Log     /messages/${user}[userid]
        Log    ${HOMEPAGE}${messages}${user}[userid]
        Run Keyword     @{arguments}
    END




Send
    [Arguments]     ${message}
    Log     The random message is ${message}

The ChatTestCase library looks like this:

class ChatTestCase:


    ROBOT_LIBRARY_SCOPE = "TEST"

    unlimited_messaging_subscriptions = ("VIP","PREMIUMPLUS","PLATINUM","GOLD")

    def __init__(self, subscription_of_sender, subscription_of_receiver, sent_message):
        self.subscription_of_sender=subscription_of_sender.upper()
        self.subscription_of_receiver=subscription_of_receiver.upper()
        self.sent_message=sent_message
        self.should_deliver_message = True
        self.count = 0


    def expected_chat_message(self):
        self.count+=1
        print(f'no of expected_chat_message method passes is {self.count}')
        #print(f'value of variable should_deliver_message is {self.should_deliver_message}')
        if self.subscription_of_sender == "BASIC" and self.subscription_of_receiver not in self.unlimited_messaging_subscriptions:
            self.should_deliver_message = False
        elif self.subscription_of_receiver == "BASIC" and self.subscription_of_sender not in self.unlimited_messaging_subscriptions:
            self.should_deliver_message = False

        if self.should_deliver_message:
            print(f'value of variable should_deliver_message is {self.should_deliver_message}')
            return self.sent_message
        else:
            print(f'value of variable should_deliver_message is {self.should_deliver_message}')
            self.should_deliver_message = True
            return "CONTACT+"

The trouble is that the Import Library keyword appears to instantiate the ChatTestCase class only once, in the first iteration. In the Robot Framework documentation it says that if a Library is imported multiple times with different arguments, it will instantiate the class for each iteration inside the FOR loop.

Robot Framework log

I have tried replacing the custom library being imported with a dummy library and the same thing happens

Anyone know if there is any way to import custom libraries dynamically from inside a FOR loop?

1
Try to call Reload Library inside the loop - I don't know will it (haven't looked at the source), but have a feeling it might help you. If it doesn't do the job, then you might consider implementing a factory pattern in the py class, to produce you the different object types based on the runtime value.Todor Minakov
You mentioned that the documentation states that the library will be imported. Can you link to that section? To my knowledge this is not the case.A. Kootstra

1 Answers

1
votes

Are you sure it should be instantiated multiple times? The keyword Import Library doesn't mention anything like that. You've read it in the user guide under library scope, but that doesn't mean it applies even for the keyword.

I found this solution which I find clumsy at best, but it works as you expect, that is you create multiple instances of one library at runtime in a for loop.

My example library:

from robot.api import logger


class TestLibrary(object):
    

    ROBOT_LIBRARY_VERSION = 1.0
    ROBOT_LIBRARY_SCOPE = 'TEST' 

    def __init__(self, num):
        self.count = 0
        self.num = num

    def log_params(self):          
        logger.console('count: {0} - num: {1}'.format(self.count, self.num))
        self.count += 1

Test case:

*** Test Cases ***
Library Imports
    FOR    ${i}    IN RANGE    1    5     
        ${name}=    Set Variable    Test${i}   
        Import Library    ${CURDIR}/../../Libraries/TestLibrary.py    ${i}    WITH NAME    ${name}          
        Set Library Search Order    ${name}
        Log Params
    END

The output is:

count: 0 - num: 1
count: 0 - num: 2
count: 0 - num: 3
count: 0 - num: 4

which is different than in your case where self.count was incremented with every iteration of the for loop.

The key here is I assign a different name (${name}) to each instance, and I search for the keyword Log Params starting from the last created instance.