From two files test_now.py and test_later.py as follows:
# test_now.py
import unittest
class CommonClass(unittest.TestCase):
def hello(self):
print "Hello there"
def bye(self):
print "Bye"
def seeYouAgain(self):
print "See You Again"
def whatsUp(self):
print "What's up?"
def testNow(self):
self.hello()
self.bye()
if __name__ == '__main__':
unittest.main()
# test_later.py
import unittest
class CommonClass(unittest.TestCase):
def hello(self):
print "Hello there"
def bye(self):
print "Bye"
def seeYouAgain(self):
print "See You Again"
def whatsUp(self):
print "What's up?"
def testLater(self):
self.hello()
self.whatsUp()
if __name__ == '__main__':
unittest.main()
I reorganize in three files as follows:
# common_class.py
import unittest
class CommonClass(unittest.TestCase):
def hello(self):
print "Hello there"
def bye(self):
print "Bye"
def seeYouAgain(self):
print "See You Again"
def whatsUp(self):
print "What's up?"
# test_now.py
from common_class import *
def testNow(self)
self.hello()
self.bye()
setattr(CommonClass, 'testNow', testNow)
if __name__ == '__main__':
unittest.main()
# test_later.py
from common_class import *
def testLater(self):
self.hello()
self.whatsUp()
setattr(CommonClass, 'testLater', testLater)
if __name__ == '__main__':
unittest.main()
What are the concerns about this DRY approach?
Modifying other modules when your module is imported is a huge wart.
Instead, create subclasses:
# test_now.py
from common_class import CommonClass
class TestNow(CommonClass):
def testNow(self)
self.hello()
self.bye()
# test_later.py
from common_class import CommonClass
class TestLater(CommonClass):
def testLater(self):
self.hello()
self.whatsUp()
Or you could just move the functions out of the class since they don't depend on anything in self.
Or, once your problem grows beyond trivial examples, maybe give up on using the standard unittest framework and use something saner like py.test so you can use proper fixtures and all sorts of things.
Related
I have got the following very simple functions and tests:
from feedback import error_msg, info_msg, warn_msg
import pytest
def test_message_info(capsys):
#info_msg
def message():
return "testmessage"
message()
assert capsys.readouterr().out == "INFO: testmessage\n"
def test_message_error(capsys):
#error_msg
def message():
return "testmessage"
message()
assert capsys.readouterr().out == "ERROR: testmessage\n"
def test_message_warning(capsys):
#warn_msg
def message():
return "testmessage"
message()
assert capsys.readouterr().out == "WARN: testmessage\n"
I know there are probably ways reduce these tests to a single test with a fixture or pytest.mark.parametrize, but I can not get my head around how to solve this. Does anyone know how to do this with a decorator?
I'd use #pytest.mark.parametrize:
import pytest
import functools
# Quickly reimplement the `feedback` decorators, so that this
# example will be runnable. These lines aren't important if
# you're just interested in the answer to the question at hand.
def log_msg(message):
def decorate(f):
#functools.wraps(f)
def wrapper(*args, **kwargs):
out = f(*args, **kwargs)
print(f'{message}: {out}')
return wrapper
return decorate
info_msg = log_msg('INFO')
error_msg = log_msg('ERROR')
warn_msg = log_msg('WARN')
# Make a parametrized test:
#pytest.mark.parametrize(
'decorator, expected', [
(info_msg, 'INFO: testmessage\n'),
(error_msg, 'ERROR: testmessage\n'),
(warn_msg, 'WARN: testmessage\n'),
],
)
def test_decorators(decorator, expected, capsys):
#decorator
def message():
return "testmessage"
message()
assert capsys.readouterr().out == expected
(Edited to make runnable, and to fix some bugs.)
Apply the decorator to the function "by hand" rather than using the decorator syntactic sugar. Then you can do all three tests in one loop.
from feedback import error_msg, info_msg, warn_msg
import pytest
MESSAGE_BY_DECORATOR = [
(info_msg, "INFO"),
(error_msg, "ERROR"),
(warn_msg, "WARN")]
def test_message_all(capsys):
def message():
return "testmessage"
for decorator, expected in MESSAGE_BY_DECORATOR:
decorated_message = decorator(message)
decorated_message()
assert capsys.readouterr().out == f"{expected}: testmessage\n"
# you'll need to reset your capsys object here
I try to order my tests but the problem is that the test_add will be first and I need that the test_remove will be first. I try to use sortTestMethodsUsing but I still get test_add as the first test.
import unittest
class TestSum(unittest.TestCase):
def test_remove(self):
print("1")
def test_add(self):
print("2")
if __name__ == '__main__':
loader = unittest.TestLoader()
loader.sortTestMethodsUsing = None
unittest.main(testLoader=loader)
Trying to call two methods say_hello and say_world by getattr() in multiprocessing.Process, but method say_world hasn't been executed. How can I make it possible? Thanks.
# -*- coding: utf-8 -*-
from multiprocessing import Process
import time
class Hello:
def say_hello(self):
print('Hello')
def say_world(self):
print('World')
class MultiprocessingTest:
def say_process(self, say_type):
h = Hello()
while True:
if hasattr(h, say_type):
result = getattr(h, say_type)()
print(result)
time.sleep(1)
def report(self):
Process(target=self.say_process('say_hello')).start()
Process(target=self.say_process('say_world')).start() # This line hasn't been executed.
if __name__ == '__main__':
t = MultiprocessingTest()
t.report()
The parameter target expects a reference to a function as value but your code passes None to it. These are the necessary parts to change:
class Hello:
def say_hello(self):
while True:
print('Hello')
time.sleep(1)
def say_world(self):
while True:
print('World')
time.sleep(1)
class MultiprocessingTest:
def say_process(self, say_type):
h = Hello()
if hasattr(h, say_type):
return getattr(h, say_type) # Return function reference instead of execute function
else:
return None
I have 2 modules: test1.py and test2.py.
test1.py
import unittest
class ArithTest (unittest.TestCase):
def test_run (self):
""" Test addition and succeed. """
self.failUnless (1+1==2, 'one plus one fails!')
self.failIf (1+1 != 2, 'one plus one fails again!')
self.failUnlessEqual (1+1, 2, 'more trouble with one plus one!')
if __name__ == '__main__':
unittest.main()
test2.py
import unittest
class AlgTest (unittest.TestCase):
def test_alg (self):
""" Test addition and succeed. """
self.assertEqual(1+1, 2, '1+1 != 2? whaaat?')
self.assertEqual(6-5, 1, '6-5 != 5 wft python?')
if __name__ == '__main__':
unittest.main()
-Now-
I wanna create a new module test3.py to test test1.py and test2.py. I don't now how, i read on internet about suit tests but i don't understand.
I don't want to create one more method with calling tests, and call them on test3.py.
I wanna group them and call in test3.py and they run as unitests
test1.py
import unittest
class ArithTest (unittest.TestCase):
def test_run (self):
""" Test addition and succeed. """
self.failUnless (1+1==2, 'one plus one fails!')
self.failIf (1+1 != 2, 'one plus one fails again!')
self.failUnlessEqual (1+1, 2, 'more trouble with one plus one!')
def runTest(self):
self.test_run()
if __name__ == '__main__':
unittest.main()
test2.py
import unittest
class AlgTest (unittest.TestCase):
def test_alg (self):
""" Test addition and succeed. """
self.assertEqual(1+1, 2, '1+1 != 2? whaaat?')
self.assertEqual(6-5, 1, '6-5 != 5 wft python?')
def runTest(self):
self.test_alg()
if __name__ == '__main__':
unittest.main()
test3.py
from .test1 import ArithTest
from .test2 import AlgTest
import unittest
def suite_2():
suite = unittest.TestSuite()
suite.addTest(ArithTest())
suite.addTest(AlgTest())
return suite
if __name__ == '__main__':
runner = unittest.TextTestRunner()
test_suite = suite_2()
runner.run(test_suite)
Also add a __init__.py
Run it with python3 -m folder_name.test3
I want to know, how can I test for a function randomly pulled from a list in a conditional statement? Here is some example code. Just ignore what the code is supposed to be printing.
import random, time
def biomeLand():
print "Biome: Land"
def biomeOcean():
print "Biome: Ocean"
def biomeDesert():
print "Biome: Desert"
def biomeForest():
print "Biome: Forest"
def biomeRiver():
print "Biome: River"
biomes = [biomeLand, biomeOcean, biomeDesert, biomeForest,
biomeRiver]
def run():
while True:
selected_biome = random.choice(biomes)()
time.sleep(0.5)
run()
Once again how can I make it so the program tests in a conditional statement when a certain function is called from the list?
maybe:
def run():
while True:
selected_biome = random.choice(biomes)
selected_biome()
if selected_biome == biomeLand:
print "biomeLand Selected"
time.sleep(0.5)
run()
You can just match them like any other variable:
def foo():
print "foo"
def bar():
print "bar"
first = foo
print (first == bar) # prints "False"
print (first == foo) # prints "True"
So in your example you can just have something like:
if selected_biome == biomeLand:
# do something