Another day, another language; such is the life of a consultant. This time it was Python and I was parameterizing tests for a client so I could log into their system without having to change anything other an an external file. Their CI server will have its own file, as will each of the team members writing / maintaining the Selenium scripts.
So building on what was covered in One, and only one config file and If you really must write your Selenium framework in Java, here is how I am currently suggesting how people incorporate configuration files into their scripts and frameworks.
First, you need to tell your framework (which in this case I mean ‘your own custom runner’) where exactly to find your config file.
import getopt # this is a custom module / class you can see below import config try: opts, args = getopt.getopt(sys.argv[1:], "hc:", ["config="]) except: print("crap") sys.exit(2) config_file = "" for o, a in opts: if o == "-h": print("Usage:") print("sh.[bat|sh] script_pattern") print(" script_pattern can be either a script name (mco_rpt_wo_0001.py) or path part (mco_rpt)") if o in ("-c", "--config"): config_file = a if config_file == "": logger.info("using config/flyingmonkey.cfg as config") config_file = "flyingmonkey.cfg" # two ways to specify the config; either as a filename in the config dir or by path cf = config.config() if os.path.exists(os.path.abspath(config_file)): cf.configure(config_file) elif os.path.exists(os.path.join(os.path.dirname(__file__), "..", "config", config_file)): cf.configure(os.path.join(os.path.dirname(__file__), "..", "config", config_file)) else: print "config file (%s) does not exist" % config_file sys.exit(1)
Basically, what is happening here is that the runner can take as an optional parameter -c or –config which both take the name of a config file. And if the parameter isn’t provided then a default of flyingmonkey.cfg is used.
In my original way of doing this almost three years ago, I had it read the config from an XML file, but that doesn’t appear to be the Pythonic way of doing things. In the standard modules that Python comes with is the ConfigParser module which is a lot nicer — and since it is there by default is implicitly blessed as the way to do this sort of thing. Here is my new class for parsing this file.
import ConfigParser class config(object): # singleton _instance = None def __new__(cls, *args, **kwargs): if not cls._instance: cls._instance = super(config, cls).__new__(cls, *args, **kwargs) return cls._instance def configure(self, config_file): # parse config self.config = ConfigParser.RawConfigParser() self.config.readfp(open(config_file))
A lot nicer.
And here is how it is used in a script.
import unittest, logging from selenium import selenium import config, rabbit class createAlert(unittest.TestCase): def setUp(self): self.log = logging.getLogger("monkey.createAlert") self.cf = config.config().config self.verificationErrors =  self.selenium = selenium("localhost", 4444, self.cf.get("General", "browser"), self.cf.get("General", "server")) self.selenium.start() rabbit.login(self.selenium, self.cf.get("Login", "username"), self.cf.get("Login", "password"))
As for the actual file that it reads from, for those who used to have to hack around in DOS and Windows 3.x, it is quite similar to the .ini format that everything used to be.
[General] server: http://flying.monkey.com environment: test browser: *chrome [Login] username: firstname.lastname@example.org password: monkey
The observant reader will see that the way to reference a particular parameter is by “Section” and then “Key”.
I’m pretty happy with how easy, and nice, it is to do this now.