passing arguments to unittest.TestSuite and using xmlrunner.XMLTestRunner - unit-testing

I am writing some tests which use the python unittest package (Python 2.7)
and I heavily rely on the xmlrunner.XMLTestRunner to dump the XML test output
Unfortunately, I fail to find some basic example which describes how one can pass some command line options to the test class to parametrise some of the tests.
Does someone have some hint on how I could achieve this (using xmlrunner)?
In addition, here is what I try to achieve:
I define my tests in a set of classes in the following myunittest.py file:
import unittest
class TestOne(unittest.TestCase):
def __init__(self, options=None):
unittest.TestCase.__init__(self)
self.__options = options
def A(self):
print self.__options.configXML # try to print the parameter
self.assertEqual(1, 1)
and call it from the main.py which looks like:
from optparse import OptionParser
import unittest
import xmlrunner
from uitest import *
def runit(opt):
suite = unittest.TestSuite()
suite.addTest(TestOne(options=opt))
testrunner = xmlrunner.XMLTestRunner(output='tests', descriptions=True)
unittest.main(testRunner=testrunner).run(suite)
if __name__ == "__main__":
parser = argparse.ArgumentParser(add_help=False)
parser.add_argument("-c", "--configXML", dest="configXML", help="xml file")
options = parser.parse_args()
runit(opt=options)
Many thanks for your valuable help.

after several hours trying to figure it out, I came to this solution, which makes my day. I post it here, in case someone comes to the same issue.
The main drawback is that it seems I need to have everything in the same python file. and I run it like:
python test.py --xmlConfig=configFile.xml --xmlRunner
with test.py:
import unittest
import sys
from optparse import OptionParser
import xmlrunner
class MyTests(unittest.TestCase):
def testFirstThing(self):
xmlConfig=options.xmlConfig
self.assertEqual(xmlConfig,"configFile.xml")
if __name__ == '__main__':
parser = OptionParser()
parser.add_option("--xmlRunner", "--xmlRunner", help="perform a unittest and generate XML", dest="xmlRunner", default=False, action='store_true')
parser.add_option("--xmlConfig", "--xmlConfig", type="string", help="configuration file", dest="xmlConfig", default="config.xml")
options, arguments = parser.parse_args()
if options.xmlRunner:
del sys.argv[1:]
unittest.main(testRunner=xmlrunner.XMLTestRunner(output='./xml'))

Related

How to prevent import (and get mock instead of module) in python2.7

I'm writing unittests for MyClass in mymodule that uses
keras.models.load_model. Every time when I run my unittests importing keras library took a few seconds and print the message: "Using TensorFlow backend."
such behavior is quite annoying. Is there a possibility to prevent importing
module in python2.7 (and get Mock() instead)?
mymodule.py:
from keras.models import load_model
class MyClass:
def __init__(self):
"""I use load_model here"""
...
test_mymodule.py
import unittest
from mock import Mock, MagicMock, patch
from mymodule import MyClass
class MyClassInitializationTestCase(unittest.TestCase):
def test_my_super_test(self):
...
While I'm not familiar with the keras lib, I think that you can make you test working by using a combination of MagicMock and modules patching.
mymodule.py:
import keras
class MyClass(object):
def __init__(self):
"""I use load_model here"""
self.example = keras.models.load_model()
test_mymodule.py:
import unittest
import sys
from mock import Mock, MagicMock, patch
sys.modules['keras'] = MagicMock() # as to be done before importing mymodules
from mymodule import MyClass
class MyClassInitializationTestCase(unittest.TestCase):
#patch('keras.models.load_model')
def test_my_super_test(self, mock_load_model):
""" super test """
fake_return_value = "bar"
mock_load_model.return_value = fake_return_value
foo = MyClass()
self.assertEqual(foo.example, fake_return_value)
mock_load_model.assert_called_once()
When I run my test I've got the expected result:
$ nosetests
.
----------------------------------------------------------------------
Ran 1 test in 0.016s
OK
I'll try to explain a bit more (I'm not an expert in unittest or mocking). First you will notice that I've change the import of your keras library. This is simply for avoiding mocking keras, then keras.models and finally keras.models.load_model. I add the MagicMock to my available modules (I don't have it installed). The MagicMock as to be before importing keras, I you case before importing mymodule.
After that, I patch keras.models.load_model for my unittest test_my_super_test. You receive your mocked method as attribute of your test, I've named the attribute mock_load_model. You can use this mocked method to define its return value. That is what I did on the line mock_load_model.return_value = fake_return_value. When I will call load_model, the method will return fake_return_value. The rest is plain unittest.
Hope it help.
To the rest of the community, please correct me if there is someting wrong with this or if there is a better way to do.

How to perform unit test for Falcon API python

I have developed an application using Falcon framework in Python language. I developed few API, Now I wanted to perform unit test so I used unittest package, But I am not able to test my APIs as it fails unittest.
For testing I refer this doc
I tried to simulate the get method but it asking me argument. Also I am unable to perform any put or post testing.
Here are my code to perform unit test
main.py
from app.api.v1 import scheduler
self.add_route('/v1/schedulers', scheduler.SchedulerCollection())
scheduler.py
class SchedulerCollection(BaseResource):
def __init__(self):
db = redis_db.RedisStorageEngine()
self.r = db.connection()
"""
Handle for endpoint: /v1/schedulers
"""
# #falcon.before(validate_scheduler_create)
def on_post(self, req, res):
#some code here
##falcon.before(auth_required)
def on_get(self, req, res):
#some code here
scheduler_test.py
import sys, os
import unittest
import json
from falcon import testing
from app.api.v1 import scheduler
class SchedulerTestCase(testing.TestCase):
def setUp(self):
super(SchedulerTestCase, self).setUp()
self.app = scheduler.SchedulerCollection.on_get
class TestMyApp(SchedulerTestCase):
def test_get_schedulers(self):
doc = {u'message': u'Hello world!'}
result = self.simulate_get('/v1/schedulers')
result = self.simulate_get('/v1/schedulers')
self.assertEqual(result.json, doc)
if __name__ == '__main__':
unittest.main()
After running test I am getting this error
Traceback (most recent call last):
File "tests/scheduler_test.py", line 17, in setUp
self.app = scheduler.SchedulerCollection().on_get(self.api_class)
TypeError: on_get() takes exactly 3 arguments (2 given)
I don't know where I am doing wrong
Any help would be highly appreciated
Thanks
First off, self.app should be initialize with your falcon app, not the method you are testing. Secondly, simulate_get is an attribute of self.app (not self).
Check more info at this answer.

Running django unit tests from shell with ipython notebook has strange behavior

I'm using an ipyhton notebook connected to Django shell to run some tests. I am on django 1.4.
First, if I run as configured below sometimes it works perfectly and other times, it just hangs with no output and no errors. I have to completely kill the ipyhton kernel and close all notebooks and try again (when the hang event occurs, all open notebooks stop working)
If i inherit from unittest.TestCase instead of django.test.TestCase it works perfect every time. However, I need the latter so i can use the django's TestCase.client in my actual tests.
NOTE: In both cases I am skipping the test database because I'm getting a failure on a missing celery database. I will cross that bridge at another time.
The notebook:
from django.utils import unittest
from django.test import TestCase
from django.test.utils import setup_test_environment
from django.test.simple import DjangoTestSuiteRunner
class MyTestCase(TestCase):
def test_001(self):
print "ok"
def test_002(self):
self.assertEqual(True , True)
if __name__ == '__main__':
setup_test_environment()
runner = DjangoTestSuiteRunner(verbosity=1, interactive=True, failfast=True)
suite = unittest.TestLoader().loadTestsFromTestCase(MyTestCase)
#old_config = runner.setup_databases()
result = runner.run_suite(suite)
#runner.teardown_databases(old_config)
runner.suite_result(suite, result)
In my case, I just created a test_runner function that accepts a test_class parameter, like this:
def test_runner(test_class):
from django.utils import unittest
from django.test.utils import setup_test_environment
from django.test.simple import DjangoTestSuiteRunner
setup_test_environment()
runner = DjangoTestSuiteRunner(verbosity=1, interactive=True, failfast=True)
suite = unittest.TestLoader().loadTestsFromTestCase(test_class)
result = runner.run_suite(suite)
runner.suite_result(suite, result)
After that, you could just run:
test_runner(MyTestCase)
in ipython notebook.
Make sure to use the one that's provided by django-extensions, by running:
manage.py shell_plus --notebook
Hope that helps.

How to transfer value from one python script class to another python script

I need to connect two python script class to each other and transfer values.
It seems that I made some mistakes to initialize the class objects and passing the
values please note the way I followed and somebody please kindly advise me on where I am getting wrong.
what is wrong with this line of code
def TransferTreeVal(objSubS):
objCM=MainScript.clsMain()
print "Transfer value"
Some more detailed code
##MainScript.py
import os
from Tkinter import *
import Tkinter as tk
import ttk
class clsMain():
def __init__ (objCM):
root['width']=500
root['height']=400
root['bg']='brown'
objCM.MethodDisplay()
def MethodDisplay(objCM):
print "display windows"
root=tk.Tk()
objCM = clsMain()
root.mainloop()
##SubScript.py
import os
from Tkinter import *
import Tkinter as tk
import ttk
import MainScript
class clsSubS():
def __init__ (objSubS):
root['width']=500
root['height']=500
root['bg']='brown'
objSubS.DispWin()
def TransferTreeVal(objSubS):
objCM=MainScript.clsMain()
print "Transfer value"
root=tk.Tk()
objSubS = clsSubS()
The main thing you are doing wrong is that you are importing files that have executable code in them. When you import SubScript.py, it is going to execute the code at the bottom which creates an instance of Tk. However, your main script also creates an instance of Tk and you should only ever have a single instance in a running program.
Normally, if you have a class you want to import, but you also want to use it as a standalone script, you "hide" the standalone script code behind a check like this:
if __name__ == "__main__":
root = tk.Tk()
objSubS = clsSubS()
With that, the code will only get executed if you do python SubScript.py. Also, when you import SubScript, that code will not run.

Testing Django view with environment variables

I am starting to write tests for a Django app, which relies on several environment variables. When I am testing it in the shell, I can import os and specify the variables and my tests work just fine. However, when I put them into tests.py, I still get a key error because those variables are not found. here's what my test looks like:
from django.utils import unittest
from django.test.utils import setup_test_environment
from django.test.client import Client
import os
os.environ['a'] = 'a'
os.environ['b'] = 'b'
class ViewTests(unittest.TestCase):
def setUp(self):
setup_test_environment()
def test_login_returning_right_template(self):
""" get / should return login.html template """
c = Client()
resp = c.get('/')
self.assertEqual(resp.templates[0].name, 'login.html')
Is this the wrong place to initialize those variables? I tried to do it on setUp, but with the same result - they are not found. Any suggestions on how to initialize environment variables before running a test suite?
Thanks!
Luka
You should not relay on os.envior in your views. If you have to, do It in your settings.py
MY_CUSTOM_SETTING = os.environ.get('a', 'default_value')
And in views use settings variable:
from django.conf.settings import MY_CUSTOM_SETTING
print MY_CUSTOM_SETTING
Then in your test you can set this setting:
from django.test import TestCase
class MyTestCase(TestCase):
def test_something(self):
with self.settings(MY_CUSTOM_SETTING='a'):
c = Client()
resp = c.get('/')
self.assertEqual(resp.templates[0].name, 'login.html')