Import Library contains no keywords - robotframework

I'm beginner to robot framework. I wanted to use my own library,do import and write test case.unfortunately I'm facing an error "Import Library contains no keywords" .I have gone through some of the posts realted to this in stack over flow ,but still i'm not able to figure out the issue in robot framework. I might be doing something silly.
Here is my code in python
class ExampleLibrary(object):
def __init__(self):
print "Hello"
def hello(self):
print "The given name"
here is the error [ WARN ] Imported library RobotFramework\TestSuite\Testclass.py' contains no keywords.
I have placed the .py file in the same directory as the test case.
Robotframework script
*** Settings ***
Library Testclass.py
*** Test Cases ***
LibraryTest
hello
Please Help
Thanks in advance

Class name of your library must be same as filename. Please have a look at this:
http://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-library-class-or-module
class Testclass(object):
def __init__(self):
print "Hello"
def hello(self):
print "The given name"

You should follow Pekka's answer or change your import as below:
*** Settings ***
Library ExampleLibrary.TestClass
From Documentation:
Python classes are always inside a module. If the name of a class implementing a library is the same as the name of the module, Robot Framework allows dropping the class name when importing the library. For example, class MyLib in MyLib.py file can be used as a library with just name MyLib. This also works with submodules so that if, for example, parent.MyLib module has class MyLib, importing it using just parent.MyLib works. If the module name and class name are different, libraries must be taken into use using both module and class names, such as mymodule.MyLibrary or parent.submodule.MyLib.

Related

There is no keyword to check a if a non regular exist on robot framework

Current implementation of keyword File Should Exist is using os.path.isfile() that returns false if is not a regular file. Is there a keyword to check non regular, as block or character device files?
I'm not aware of such a keyword. But if you can do it in Python, you can do it in RF.
Example Python function you can turn into RF keywords:
Libraries/file-utils.py
import os, stat
from robot.utils.asserts import assert_true
def block_file_should_exist(file):
assert_true(stat.S_ISBLK(os.stat(file).st_mode))
def character_file_should_exist(file):
assert_true(stat.S_ISCHR(os.stat(file).st_mode))
and an example test:
*** Settings ***
Library ../Libraries/file-utils.py
*** Test Cases ***
Character File Exists
Character File Should Exist /dev/zero

nose.run returns blank file when used with xunit arguments

I am using nose to run my tests the following way
import nose
import unittest
if __name__ == "__main__":
test_cases = unittest.TestLoader().discover(<path_to_test_files>)
suite = unittest.TestSuite([test_cases])
xunit_report = True
log_file = 'my_report.xml'
arguments = ["nosetest",'--verbosity=2']
if xunit_report:
arguments += ['--with-xunit', '--xunit-file', log_file]
nose.run(suite=suite, argv=arguments)
The suite variable is updated with all the test cases discovered. The console log also validates that all the tests got executed.
However, the xml result file always contains
<?xml version="1.0" encoding="UTF-8"?><testsuite name="nosetests" tests="0" errors="0" failures="0" skip="0"></testsuite>
Am on Python 2.7.14.
What do I need to change to get the actual results in my xml file?
If you change the discover() call to a provide a path, like . for the current directory:
test_cases = unittest.TestLoader().discover('.')
Then the loader will find files in the working directory that you are executing the script from that match the pattern 'test*.py'. If I add add your script to a file run.py, and a test next to it in a file named test_example.py, with the following UnitTest test:
import unittest
class TestStringMethods(unittest.TestCase):
def test_upper(self):
self.assertEqual('foo'.upper(), 'FOO')
Then the output xml file contains the expected test results.
So: Make sure you're running the script from the same directory your tests are in (or that you change .discover('.') to whatever directory your tests are in, and that your test files match the test*.py pattern.
Also note that that nose.run(..) has an argument for just a module name to find tests in that you may find useful:
nose.run(module=".")

How to add a python module which uses Sel2Lib without getting multiple keyword error?

I'm trying to import a python module to ride for more than 3 hours with no success. I went through the steps explained in fourth answer here where it suggests to create a python module Selenium2LibraryExt.
How to get All Text in robot framework ?
the problem that i observe is that since i use Selenim2Library in my other codes of the same test now i import Selenium2LibraryExt which inherits from Selenim2Library, my test doesn't know anymore that e.g. Click Element keyword comesfrom Selenim2Library or Selenium2LibraryExt and it gives me multiple keyword error
So i did
1-I removed
from Selenium2Library import Selenium2Library
from the head of my python module but i let it stay as a library in my test case: settings
Library Selenium2Library
it didn't work out. 2-Then i removed
Library Selenium2Library
from my test case but added:
from Selenium2Library import Selenium2Library
in the head of my python module.
but in both cases i get errors. how should i do not to have 2 selenium2library libraries seen by my test?
Thanks
If you go with a library that inherits, then your test data needs to import either Selenium2Library or your custom library, but not both. If you only import through a shared resource file, and not directly in the tests, this is easier to control.
Another option is to create a library that extends Selenium2Library without replacing it:
from robot.libraries.BuiltIn import BuiltIn
class Selenium2LibraryExt(object):
#property
def _s2l(self):
return BuiltIn().get_library_instance('Selenium2Library')
def get_all_texts(self, locator):
"""Returns the text values of elements identified by `locator`."""
elements = self._s2l._element_find(locator, False, True)
return [e.text for e in elements]
If you are using a recent version of Selenium2Library (>= 1.7), Get Webelement and Get Webelements allow you to do a lot of things there are not keyword for...
#{texts} Create List
#{elems} Get Webelements some locator
:FOR ${elem} IN #{elems}
\ ${text} Get Text ${elem}
\ Append To List ${texts} ${text}
Same thing but getting the text using the extended variable syntax to work with a webelement.
#{texts} Create List
#{elems} Get Webelements some locator
:FOR ${elem} IN #{elems}
\ Append To List ${texts} ${elem.text}
Or in Python:
from robot.libraries.BuiltIn import BuiltIn
class Selenium2LibraryExt(object):
def get_all_texts(self, locator):
"""Returns the text values of elements identified by `locator`."""
s2l = BuiltIn().get_library_instance('Selenium2Library')
elements = s2l.get_webelements(locator)
# or elements = BuiltIn().run_keyword('Get Webelements', locator)
return [e.text for e in elements]
See also https://stackoverflow.com/a/35323931/2532697
So you can easily get around this by specifying the particular library you want to use. For example:
Selenium2LibraryExt.Click Element

Is it possible to write Robot Framework tests (not keywords) in Python?

Is it possible to write Robot Framework tests in Python instead of the .txt format?
Behind the scenes it looks like the .txt test get converted into Python by pybot so I'm hoping that this is simply a matter of importing the right library and inheriting from the right class but I haven't been able to figure out how to do that.
(We already have a bunch of suites and have keywords written in both formats but sometimes the RF syntax makes it very difficult to do things that are simple in Python. I understand it would be possible to just write a Python keyword for each test plus 'wrap' setup and teardown functions the same way, but that seems cumbersome.)
Robot does not convert your test cases to python behind the scenes before running them. Instead, it parses the test cases, then iterates over each keyword, calling the code that implements the keyword. There isn't ever a stage where there's a completely pure python representation of a test case.
It is not possible to write tests in python, and have those tests run alongside traditional robot tests by the provided test runner. Like you said in your question, your only option is to put all of your logic for a single test case in a single keyword, and call that keyword from a test case.
It is possible to create and execute tests in python solely via the published API. This might not be what you're really asking for, because ultimately you're still creating keywords, you're just creating them via python.
from robot.api import TestSuite
suite = TestSuite('Activate Skynet')
suite.imports.library('OperatingSystem')
test = suite.tests.create('Should Activate Skynet', tags=['smoke'])
test.keywords.create('Set Environment Variable', args=['SKYNET', 'activated'], type='setup')
test.keywords.create('Environment Variable Should Be Set', args=['SKYNET'])
The above example was taken from here:
http://robot-framework.readthedocs.org/en/2.8.1/autodoc/robot.running.html
Well, you should not care if your python code represents tests or keywords as long as you code the logic of the tests in python.
The best you can do is to keep some html tables in robot format. Each line would be a call for a keyword. The keyword could be implemented in python, and, logically, represents a whole test (although in robot terminology it is still a "keyword").
This post shows how you can have access to the robot context from your python code.
robot variables
BuiltIn().get_variable_value("${USERNAME}")
java keywords
from com.mycompany.myproject.testtools import LoginRobotKeyword
LoginRobotKeywords().login(user, pwd)
robot keywords
BuiltIn().run_keyword("check user connected", user)
Robotframework does not support writting test cases in python directly. I've submitted an enhancement PR, check it here
https://github.com/robotframework/robotframework/issues/3128
But I've tried to do that by moving all the test cases logic to python code, and make RF test cases just a entry point to them.
Here is an example.
We could create a python file to include all testing logic and setup/teardown logic, like this
# *** case0001.py *****
from SchoolClass import SchoolClass
schCla = SchoolClass()
class case0001:
def steps(self):
print('''\n\n***** step 1 **** add school class \n''')
self.ret1 = schCla.add_school_class('grade#1', 'class#1', 60)
assert self.ret1['retcode'] == 0
print('''\n\n***** step 2 **** list school class to check\n''')
ret = schCla.list_school_class(1)
schCla.classlist_should_contain(ret['retlist'],
'grade#1',
'class#1',
60,
self.ret1['id'])
def setup(self):
pass
def teardown(self):
schCla.delete_school_class(self.ret1['id'])
And then we creat a Robot file. In which all RF test cases are in the same form and just work as entry points to python test cases above.
like this
*** Settings ***
Library cases/case0001.py WITH NAME C000001
Library cases/case0002.py WITH NAME C000002
*** Test Cases ***
add class - tc000001
[Setup] C000001.setup
C000001.steps
[Teardown] C000001.teardown
add class - tc000002
[Setup] C000002.setup
C000002.steps
[Teardown] C000002.teardown
You could see, in this way, the RF testcases are similar. We could even create a tool to auto generate them by scanning Python testcases.

Does sbt have something like gradle's processResources task with ReplaceTokens support?

We are moving into Scala/SBT from a Java/Gradle stack. Our gradle builds were leveraging a task called processResources and some Ant filter thing named ReplaceTokens to dynamically replace tokens in a checked-in .properties file without actually changing the .properties file (just changing the output). The gradle task looks like:
processResources {
def whoami = System.getProperty( 'user.name' );
def hostname = InetAddress.getLocalHost().getHostName()
def buildTimestamp = new Date().format('yyyy-MM-dd HH:mm:ss z')
filter ReplaceTokens, tokens: [
"buildsig.version" : project.version,
"buildsig.classifier" : project.classifier,
"buildsig.timestamp" : buildTimestamp,
"buildsig.user" : whoami,
"buildsig.system" : hostname,
"buildsig.tag" : buildTag
]
}
This task locates all the template files in the src/main/resources directory, performs the requisite substitutions and outputs the results at build/resources/main. In other words it transforms src/main/resources/buildsig.properties from...
buildsig.version=#buildsig.version#
buildsig.classifier=#buildsig.classifier#
buildsig.timestamp=#buildsig.timestamp#
buildsig.user=#buildsig.user#
buildsig.system=#buildsig.system#
buildsig.tag=#buildsig.tag#
...to build/resources/main/buildsig.properties...
buildsig.version=1.6.5
buildsig.classifier=RELEASE
buildsig.timestamp=2013-05-06 09:46:52 PDT
buildsig.user=jenkins
buildsig.system=bobk-mbp.local
buildsig.tag=dev
Which, ultimately, finds its way into the WAR file at WEB-INF/classes/buildsig.properties. This works like a champ to record build specific information in a Properties file which gets loaded from the classpath at runtime.
What do I do in SBT to get something like this done? I'm new to Scala / SBT so please forgive me if this seems a stupid question. At the end of the day what I need is a means of pulling some information from the environment on which I build and placing that information into a properties file that is classpath loadable at runtime. Any insights you can give to help me get this done are greatly appreciated.
The sbt-buildinfo is a good option. The README shows an example of how to define custom mappings and mappings that should run on each compile. In addition to the straightforward addition of normal settings like version shown there, you want a section like this:
buildInfoKeys ++= Seq[BuildInfoKey](
"hostname" -> java.net.InetAddress.getLocalHost().getHostName(),
"whoami" -> System.getProperty("user.name"),
BuildInfoKey.action("buildTimestamp") {
java.text.DateFormat.getDateTimeInstance.format(new java.util.Date())
}
)
Would the following be what you're looking for:
sbt-editsource: An SBT plugin for editing files
sbt-editsource is a text substitution plugin for SBT 0.11.x and
greater. In a way, it’s a poor man’s sed(1), for SBT. It provides the
ability to apply line-by-line substitutions to a source text file,
producing an edited output file. It supports two kinds of edits:
Variable substitution, where ${var} is replaced by a value. sed-like
regular expression substitution.
This is from Community Plugins.

Resources