How to create test site structure before each plone.app.robotframework-based test? - plone

I can't find a way to having something like setUp and tearDown when running a Plone robot test.
What I need is to create a whole site structure before each test. The only way I found is to create my own new robot keyword that create the structure from the browser itself, but I don't want to test the folder creation. This will slow down my tests for nothing.
I found something promising in the robotsuite library: https://github.com/collective/robotsuite/blob/b52000c65ea96b2be697bf899829c397985fc5aa/src/robotsuite/init.py#L217
However I can't make it works: I can define an empty setUp function, with no Plone context.
How can I do this?

At first, you can always define your test site structure in the setup methods of your plone.app.testing based test layer. (See docs for plone.app.testing for details.)
In addition to that, there are at least a few ways to build test site structure for plone.app.robotframework based Selenium tests:
The first is passing your test setUp function as setUp-keyword argument for RobotTestSuite-class:
import unittest
import robotsuite
from plone.testing import layered
from my.package.testing import MY_PACKAGE_ROBOT_TESTING
from zope.component.hooks import getSite
from transaction import commit
def mySetUp(testCase=None):
site = getSite()
# do stuff
commit()
def test_suite():
suite = unittest.TestSuite()
suite.addTests([
layered(
robotsuite.RobotTestSuite('test_something.robot',
setUp=mySetUp),
layer=MY_PACKAGE_ROBOT_TESTING
),
])
return suite
There should be no need for explicit tearDown, because plone.app.testing's functional test teardown already reverts all changes made to the test sandbox.
This feature is based on RobotTestSuite built to mimic DocTestSuite from doctest-module. The setUp-method takes a single argument, the test case object, but because the test layer is lost somewhere in the test framework, getSite is the only sane way to reach the portal object.
Finally, it's good to know that this approach works only as long as the Robot Framework test is executed within the same process where Plone test layer is built (which is the case when executing robosuite-wrapped test suites with e.g. zope.testrunner).
The second way would be to split the setUp function into a custom local python keyword library. For example, in my/package/testing.py you could have:
from plone import api
from transaction import commit
class MyPackageKeywords(object):
def create_stuff(self, stuff_id):
portal = api.portal.get()
obj = api.content.create(
type='Document',
title='My Stuff',
container=portal
)
commit()
return obj.absolute_url()
And you should be able to use it like:
*** Settings ***
...
Library my.package.testing.MyPackageKeywords
*** Test Cases ***
...
${URL} = Create stuff stuff_id=my-stuff
Go to  ${URL}
Element should contain css=h1.documentFirstHeading My Stuff
This has the same limitation as the first approach.
The third possible way is to create the content in the actual Robot Framework test suites by using the content related remote keywords provided in the recent plone.app.robotframework releases.
In short, this is done by including REMOTE_LIBRARY_BUNDLE_FIXTURE in your test layer and using its Create content and Fire transition keywords for creating the required mock content.
import unittest
import robotsuite
from plone.app.robotframework.testing import REMOTE_LIBRARY_BUNDLE_FIXTURE
from plone.app.testing import PLONE_FIXTURE
from plone.testing import layered
from plone.testing import z2
PLONE_ACCEPTANCE_TESTING = z2.FunctionalTesting(
bases=(REMOTE_LIBRARY_BUNDLE_FIXTURE,
PLONE_FIXTURE,
z2.ZSERVER_FIXTURE),
name="Acceptance")
def test_suite():
suite = unittest.TestSuite()
suite.addTests([
layered(
robotsuite.RobotTestSuite('test_something.robot'),
layer=PLONE_ACCEPTANCE_TESTING
),
])
return suite
*** Settings ***
Resource plone/app/robotframework/keywords.robot
Resource Selenium2Screenshots/keywords.robot
Library Remote ${PLONE_URL}/RobotRemote
Test Setup Open test browser
Test Teardown Close all browsers
*** Test Cases ***
Scenario: View folder contents
Given a contributor
and a folder
and a document inside the folder
when at the folder listing
then can see the document title
*** Variables ***
${FOLDER_ID} a-folder
${DOCUMENT_ID} a-document
*** Keywords ***
A contributor
Enable autologin as Contributor
A folder
Create content type=Folder
... id=${FOLDER_ID}
... title=A folder
... description=This is the folder
A document inside the folder
Create content type=Document
... container=/${PLONE_SITE_ID}/${FOLDER_ID}
... id=${DOCUMENT_ID}
... title=A document
... description=This is the document
... text=<p><strong>Hello world!</strong></p>
At the folder listing
Go to ${PLONE_URL}/${FOLDER_ID}/folder_contents
Element should be visible name=folderContentsForm
Can see the document title
Page should contain A document
Capture and crop page screenshot folder-contents.png css=#content
Plese note, that Create content -keyword may also require use of Enable autologin as -keyword to authenticate the content creation calls. Also note, that Capture and crop page screenshot is nowadays in a separate package robotframework-selenium2screenshots.
Content creation keywords are not yet perfect and issues may be reported at GitHub. You can also implement your own remote python keywords. They are just methods in simple python classes, which is wrapped into REMOTE_LIBRARY_BUNDLE_FIXTURE.
Finally, see also the good known versions for plone.app.robotframework and friends.

Related

Katalon - Using different Test data file for a test case depending on environment

I'd like to have the option to run my tests with different test data depending on the environment I'm in, as they are slightly different.
My current setup: Test suite -> Test Cases each with 1 test data (excel file). I run checks (based off execution profile) to determine the environment and adjust the domain URL accordingly.
If I add a second data file to a test case, is there a way I can add logic to pick a specific test data file during execution time?
If you want to use "excel_file_1" for "default" execution profile, and "excel_file_2" for other execution profiles, use this:
import com.kms.katalon.core.configuration.RunConfiguration as RC
import com.kms.katalon.core.testdata.TestDataFactory as TestDataFactory
if (RC.getExecutionProfile()=='default'){
def data = TestDataFactory.findTestData("excel_file_1")
} else {
def data = TestDataFactory.findTestData("excel_file_2")
}
Just for clarity, I will explain most of the process to accomplish this.
You could create different profiles for this (Generally used for environment variables).
Katalon Profiles
You may then enter keywords (which are GlobalVariables) to get or set
your data (URLs, locations, etc.)
Remember to add your test case(s) in a test suite
You may then create separate build commands to test each profile you
created by clicking Build CMD & specifying the execution profile
Specify profile in Build CMD
This way you can use something like TeamCity to run each cases or a combination thereof
I don't think this works as Katalon have more that one Test Case in test suite
import com.kms.katalon.core.configuration.RunConfiguration as RC
import com.kms.katalon.core.testdata.TestDataFactory as TestDataFactory
if (RC.getExecutionProfile()=='default'){
def data = TestDataFactory.findTestData("excel_file_1")
} else {
def data = TestDataFactory.findTestData("excel_file_2")
}
In above code below question comes
whats 'data' variable
what if we have few more test cases and that too have data sheet

Is there any way to display screenshot into log.html created by external python lib?

I am beginner of robot framework so that prefer to use external python library with selenium.
Since robot framework log.html is really cool, I want to put my screenshot and test result into robot framework log.html.
Is there anyway to put screenshot created by external python lib into log.html in robotframework?
In general most of the out-of-the-box keywords map to a single Python function. This makes the suggestion from #BryanOakley the right one. Have a look at the code of Robot Framework itself to learn how it does it.
In this case I think you can learn the most from looking at the code of the Screenshot library. The Python code for this library is accessible in GitHub. Given that the question is about adding them to the log, the focus should be on two functions starting on line 230. The first one adds an image file reference to the log, and the second one adds just the hyperlink.
def _embed_screenshot(self, path, width):
link = get_link_path(path, self._log_dir)
logger.info('<img src="%s" width="%s">'
% (link, link, width), html=True)
def _link_screenshot(self, path):
link = get_link_path(path, self._log_dir)
logger.info("Screenshot saved to '%s'."
% (link, path), html=True)
The actual function logger.info that is called, can be found in the Robot Framework API classes and is imported at the start of the file:
from robot.api import logger

Robot Framework: Populating parameters based off of a robot.properties file?

I am attempting to mock-up a 'robot.properties' file to be utilized within my test cases with the Robot Framework. Inside my robot.properties file it contains things like for example:
project.username=stackoverflow
inside my test case file I have tried several times to 'import' the robot.properties file via adding within Settings: Resource ../path/to/properties and etc (see directory structure below), but when I attempt to pass 'project.username' as an argument to a test it passes it as the literal string value 'project.username' and not the value 'stack overflow'. I am new to Robot, I have implemented this in other languages like Java/C#, but I fully assume that the import is preventing me from accessing my value. Any help would be greatly appreciated, unfortunately this way of driving testing isn't really referenced much online that I can find.
Dir Structure:
Tests/Acceptance/MyTestCase.robot
Tests/robot.properties
If I try Library ../robot.properties I get:
"Import by filename is not supported"
If I try Resource ../robot.properties I get:
"Unsupported file format .properties"
Robot framework doesn't support a ".properties" file.
One solution is to use a variable file, which lets you define variables in python. Since you want to use dot notation, one way is to create a class and define your variables as properties of the class. The variable file can then make an instance of that class as a variable, and you can use extended variable syntax to access the variables.
The advantage to using a variable file over a plain text file is that you can create variables dynamically by calling other python functions. As a simple example, you could create a variable called "now" that contains the current date, or "host" that is the hostname of the machine running the test.
Example:
properties.py
import platform
class Properties(object):
username = "stackoverflow"
password = "SuperSecret!"
hostname = platform.uname()[1]
properties = Properties()
example.robot
*** Settings ***
Variables properties.py
Suite Setup log running on ${properties.hostname}
*** Test Cases ***
Example
should be equal ${properties.username} stackoverflow

spring boot/spring web app embedded version number

What are the strategies to embed a unique version number in a Spring application?
I've got an app using Spring Boot and Spring Web.
Its matured enough that I want to version it and see it displayed on screen at run time.
I believe what you are looking for is generating this version number during build time (Usually by build tools like Ant, Maven or Gradle) as part of their build task chain.
I believe a quite common approach is to either put the version number into the Manifest.mf of the produced JAR and then read it, or create a file that is part of the produced JAR that can be read by your application.
Another solution would be just using Spring Boot's banner customization options described here: http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-spring-application.html#boot-features-banner
However, this will only allow you to change spring-boot banner.
I also believe that Spring Boot exposes product version that is set in Manifest.MF of your application. To achieve this you will need to make sure Implementation-Version attribute of the manifest is set.
Custom solution for access anywhere in the code
Lets assume you would like to have a version.properties file in your src/main/resources that contains your version information. It will contain placeholders instead of actual values so that these placeholders can be expanded during build time.
version=${prodVersion}
build=${prodBuild}
timestamp=${buildTimestamp}
Now that you have a file like this you need to fill it with actual data. I use Gradle so there I would make sure that processResources task which is automatically running for builds is expanding resources. Something like this should do the trick in the build.gradle file for Git-based code:
import org.codehaus.groovy.runtime.*
import org.eclipse.jgit.api.*
def getGitBranchCommit() {
try {
def git = Git.open(project.file(project.getRootProject().getProjectDir()));
def repo = git.getRepository();
def id = repo.resolve(repo.getFullBranch());
return id.abbreviate(7).name()
} catch (IOException ex) {
return "UNKNOWN"
}
}
processResources {
filesMatching("**/version.properties") {
expand (
"prodVersion": version,
"prodBuild": getGitBranchCommit(),
"buildTimestamp": DateGroovyMethods.format(new Date(), 'yyyy-MM-dd HH:mm')
)
}
}
processResources.outputs.upToDateWhen{ false }
In the code about the following is happening:
We defined a function that can take a build number out of the VCS
(in this case Git). The commit hash is limited to 7 characters.
We configure the processResources task to process
version.properties file and fill it with our variables.
prodVersion is taken from Gradle project version. It's usually set
as version in gradle.properties file (part of the general build
setup).
As a last step we ensure that it's always updated (Gradle
has some mechanics to detect if files ened to be processed
Considering you are on SVN, you will need to have a getSvnBranchCommit() method instead. You could for instance use SVNKit or similar for this.
The last thing that is missing now is reading of the file for use in your application.
This could be achieved by simply reading a classpath resource and parsing it into java.util.Properties. You could take it one step further and for instance create accessor methods specifically for each field, e.g getVersion(), getBuild(), etc.
Hope this helps a bit (even though may not be 100% applicable straight off)
Maven can be used to track the version number, e.g.:
<!-- pom.xml -->
<version>2.0.3</version>
Spring Boot can refer to the version, and expose it via REST using Actuator:
# application.properties
endpoints.info.enabled=true
info.app.version=#project.version#
Then use Ajax to render the version in the browser, for example using Polymer iron-ajax:
<!-- about-page.html -->
<iron-ajax auto url="/info" last-response="{{info}}"></iron-ajax>
Application version is: [[info.app.version]]
This will then show in the browser as:
Application version is: 2.0.3
I'm sure you've probably figured something out since this is an older question, but here's what I just did and it looks good. (Getting it into the banner requires you to duplicate a lot).
I'd recommend switching to git (it's a great SVN client too), and then using this in your build.gradle:
// https://github.com/n0mer/gradle-git-properties
plugins {
id "com.gorylenko.gradle-git-properties" version "1.4.17"
}
// http://docs.spring.io/spring-boot/docs/current/reference/html/deployment-install.html
springBoot {
buildInfo() // create META-INF/build-info.properties
}
bootRun.dependsOn = [assemble]
And this in your SpringBoot application:
#Resource
GitProperties props;
#Resource
BuildProperties props2;
Or this way to expose those properties into the standard spring environment:
#SpringBootApplication
#PropertySources({
#PropertySource("classpath:git.properties"),
#PropertySource("classpath:META-INF/build-info.properties")
})
public class MySpringBootApplication {
and then referencing the individual properties as needed.
#Value("${git.branch}")
String gitBranch;
#Value("${build.time}")
String buildTime;

How do I tell robot-server to reset the test fixture when I use ride with Plone?

I'm trying to write my first robot test; I'd like to use ride as advertized in http://developer.plone.org/reference_manuals/external/plone.app.robotframework/happy.html#install-robot-tools
I added
initialization =
import os
os.environ['PATH'] = os.environ['PATH'] + os.pathsep + '${buildout:directory}/bin'
to my [robot] section to make it possible to run the tests clicking "Start" in ride.
It works, but the second time I run the tests I still see the content created by the first test run.
How do I tell robot-server to go back to a just-initialized state?
Easily (and you should throw me into pool for not documenting this yet in plone.app.robotframework's documentation – I thought that RIDE is too difficult to get running until it works on wxPython 2.9).
In RIDE
select Run-tab
change Execution Profile to custom script
click browse to select for bin/robot from your buildout as the Script to run tests
Click Start.
Technically bin/robot is a shortcut for bin/pybot --listener plone.app.robotframework.RobotListener (I keep repeating bin/, because it's important that plone.app.robotframework is available in sys.path). Robot Framework Listener -interface is specified in Robot Framework User Guide.
Our listener calls bin/robot-server (using XML-RPC) before every test to testSetUp-methods for the current test layer and after every test testTearDown-methods. This resets the fixture and isolates functional tests.

Resources