Output is empty when mocking input in Python Unit Test - python

So I've been having this issue for some time and can't find a solution.I have this run code which is pretty basic. I want to test for the expected output, "TEST" ,when I use side_effects to mock the input. The first time the input function is called I mock 'y' and then I mock '1' the second time it's called, which should then trigger the print statement. The problem is the output that is coming back is empty. I don't know whats going on, but when I run the main method manually and enter the inputs I get the expected output so I know the run code works as intended, but something funky is happening during the test.
here is my run code
def main():
newGame = input("")
if newGame == 'y':
print("1.Scallywag\n2.Crew\n3.Pirate")
difficulty = input("")
if difficulty == '1':
print("TEST")
main()
and here is my test code
import unittest
from unittest.mock import patch
import io
import sys
from Run import main
class MyTestCase(unittest.TestCase):
#patch('builtins.input', side_effects=['y','1'])
def test_output(self,m):
saved_stdout = sys.stdout
try:
out = io.StringIO()
sys.stdout = out
main()
output = out.getvalue().strip()
self.assertIn("TEST", output)
finally:
sys.stdout = saved_stdout
if __name__ == "__main__":
unittest.main()
and here is the AssertionError i get back along with the trace back, take note that its expecting "" which shouldn't be the case.
F
======================================================================
FAIL: test_output (__main__.MyTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Python33\lib\unittest\mock.py", line 1087, in patched
return func(*args, **keywargs)
File "C:\Users\jsalce\Desktop\Testcases\Test.py", line 20, in test_output
self.assertIn("TEST", output)
AssertionError: 'TEST' not found in ''
----------------------------------------------------------------------
Ran 1 test in 0.006s
FAILED (failures=1)
Thank you all in advance

You patch for input does not work as required because you are not giving it a function. Try this:
import unittest
from unittest.mock import patch, MagicMock
import io
import sys
from Run import main
class MyTestCase(unittest.TestCase):
##patch('builtins.input', side_effects=['y','1'])
#patch('builtins.input', MagicMock(side_effect=['y','1']))
def test_output(self):
saved_stdout = sys.stdout
try:
out = io.StringIO()
sys.stdout = out
main()
output = out.getvalue().strip()
self.assertIn("TEST", output)
#I used equals to see if I am truly grabbing the stdout
#self.assertEquals("TEST", output)
finally:
sys.stdout = saved_stdout
if __name__ == "__main__":
unittest.main(verbosity=2)
And also, you do not need variable 'm' in your test_output signature.

Print("String", file=out)
Is what you're looking for, you'll need to pass out to main though.

Related

Mute printing of an imported Python script

I want to import a python script in to another script.
$ cat py1.py
test=("hi", "hello")
print test[0]
$ cat py2.py
from py1 import test
print test
If I execute py2.py:
$ python py2.py
hi
('hi', 'hello')
Can I anyway mute the first print which is coming from the from py1 import test?
I can't comment the print in py1, since it is being used somewhere else.
py1.py use an if __name__=="__main__":
So like your py1.py would look like:
def main():
test=("hi", "hello")
print test[0]
if __name__=="__main__":
main()
This will allow you to still use py1.py normally, but when you import it, it won't run the main() function unless you call it.
This explains what's going on
Simply open the /dev/null device and overwrite the sys.stdout variable to that value when you need it to be quiet.
import os
import sys
old_stdout = sys.stdout
sys.stdout = open(os.devnull, "w")
from py1 import test
sys.stdout = old_stdout
print test
You might want to consider changing the other script to still print when its run 'in the other place' - if you're running py1 as a shell command, try to make sure all "executable statements" in a file are inside a block.
if __name__ == "__main__":
print test
(see What does if __name__ == "__main__": do?)
This would fix the underlying issue without having you do weird things (which would be redirecting the standard out, and then putting it back etc), or opening the file and executing line by line on an if block.
You could implement this functionality with methods:
py1.py
test=("hi", "hello")
def print_test():
print(test)
def print_first_index():
print(test[0])
py2.py
import py1
py1.print_test()
As MooingRawr pointed out, this would require you to change whichever classes use py1.py to import it and call the py1.print_first_index() function which may not be to your liking.

Python stderr for imported class

I am trying to pipe the error messages to a file in my python script. I have it working fine for the most part. The problem comes when I import another file, and there is an error in that file. Here is an example (logger.py):
import time
import sys
import test
class Logger(object):
def __init__(self,outputType):
self.outputType=outputType;
self.log = open("serverLog.log", "w")
def write(self, message):
self.log = open("serverLog.log", "a")
self.log.write(message)
self.log.close()
sys.stdout = Logger("stdout")
sys.stderr = Logger("stderr")
j=0
while 3<4:
print "Sdf"
j=j+1
if j>4:
print k
time.sleep(1)
The above file works fine for logging the output and errors (when test.py is not imported).
Here is the second file that I am importing (test.py) with an intentional error:
import time
time.sleep(1)
print x
When I run logger.py, all of the output and errors go to serverLog.log, except for the error cause by the import of test.py.
I am wondering if it is possible to pipe the error messages from test.py to serverLog.log without adding anything to test.py.
You should define any modules after:
sys.stdout = Logger("stdout")
sys.stderr = Logger("stderr")
And result will be:
cat serverLog.log
Traceback (most recent call last):
File "/root/untitled/x.py", line 16, in <module>
import test1
File "/root/untitled/test1.py", line 3, in <module>
print x
NameError: name 'x' is not defined
My code:
import time
import sys
class Logger(object):
def __init__(self,outputType):
self.outputType=outputType;
self.log = open("serverLog.log", "w")
def write(self, message):
self.log = open("serverLog.log", "a")
self.log.write(message)
self.log.close()
sys.stdout = Logger("stdout")
sys.stderr = Logger("stderr")
import test1
j=0
while 3<4:
print "Sdf"
j=j+1
if j>4:
print k
time.sleep(1)
The problem here is that I think you think import creates a new thread. Here are the lines of code that are being executed:
import time
<all the code in time>
import sys
<all the code in sys>
import test
import time # Now we're in test.py
time.sleep(1) # We're still in the main thread!
print x
The python interpreter then produces the error. None of your Logger code ever gets executed. The solution, as Valeriy has given, is to put the Logger code before you import test.

Checking if correct value is outputed Python unit test

I tried to word the title as clearly as possible. I'm new to unit testing, and I have a handle on some of the more basic types of assertions, but there is one test I haven't figured out. So I have user enter some type of input and I print the output by calling the variable preceding some type of message. Here is the py file the testsuite is testing
def get_input()
pirateInput = input("What be ye name?! ")
print("Ahoy Captain ", pirateInput)
The user enters a name and I just print it out. So the expected output should be "Ahoy Captain [user input]"
Here is my test suite
import unittest
from unittest.mock import patch
from get_input import *
class GetInputTest(unittest.TestCase):
def test_ValuePrints(self):
#patch input as 'Hook'
#patch('builtins.input', return_value='Hook'
saved_stdout = sys.stdout
try:
out = io.StringIO()
sys.stdout = out
get_input()
output = out.getvalue().strip()
assert output == 'Ahoy Captain Hook'
finally:
sys.stdout = saved_stdout
if __name__ == "__main__":
unittest.main()
So I check for the output I'm expecting, but the test does patch the input as expected. I don't know if I'm clear but hopefully someone can help. If you need more detail please let me know.
Thanks
The problem is pretty simple. The print function already adds a space between each pair of arguments, so if you do
print("Ahoy Captain ", pirateInput)
It will print: Ahoy Captain Hook. Notice the two spaces, the one you add at the end of the first string and the one added by print. Just remove the one in your string and it will work.
Here's a full working example:
import unittest
import sys
import io
import logging
from unittest.mock import patch
def get_input():
pirateInput = input("What be ye name?! ")
print("Ahoy Captain", pirateInput)
class GetInputTest(unittest.TestCase):
#patch('builtins.input', return_value='Hook')
def test_ValuePrints(self, sth):
log = logging.getLogger( "SomeTest.testSomething" )
saved_stdout = sys.stdout
try:
out = io.StringIO()
sys.stdout = out
get_input()
output = out.getvalue().strip()
log.debug(output)
assert output == 'Ahoy Captain Hook'
finally:
sys.stdout = saved_stdout
if __name__ == "__main__":
logging.basicConfig( stream=sys.stderr )
logging.getLogger( "SomeTest.testSomething" ).setLevel( logging.DEBUG )
unittest.main()
Test run:
$ python3 main.py
DEBUG:SomeTest.testSomething:Ahoy Captain Hook
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK

AttributeError: 'TextTestResult' object has no attribute 'assertIn'

I am trying some Python with selenium, I have some defined tests in simpleUsageUnittest.py:
import unittest
import time
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
class PythonOrgSearch(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Firefox()
# #unittest.skip("skip test_001")
def test_001_search_in_python_org(self):
driver = self.driver
driver.get("http://www.python.org")
self.assertIn("Python", driver.title)
elem = driver.find_element_by_name("q")
elem.send_keys("selenium")
elem.send_keys(Keys.RETURN)
# #unittest.skip("skip test_002")
def test_002_goole_and_stack_test_test(self):
driver_g = self.driver
driver_g.get("http://www.google.com")
self.assertIn("Google", driver_g.title)
body_g = driver_g.find_element_by_tag_name("body")
body_g.send_keys(Keys.CONTROL + 't')
driver_g.get("http://stackoverflow.com")
self.assertIn("Stack", driver_g.title)
def tearDown(self):
self.driver.close()
if __name__ == "__main__":
unittest.main(warnings = 'ignore')
Alone this set is working perfectly, but then I am trying to create some suite, testTestSuite.py:
import unittest
import simpleUsageUnittest
import sys
def suite():
testSuite = unittest.TestSuite()
testSuite.addTest(simpleUsageUnittest.PythonOrgSearch.setUp)
testSuite.addTest(simpleUsageUnittest.PythonOrgSearch.test_001_search_in_python_org)
testSuite.addTest(simpleUsageUnittest.PythonOrgSearch.test_002_goole_and_stack_test_test)
testSuite.addTest(simpleUsageUnittest.PythonOrgSearch.tearDown)
return testSuite
if __name__ == "__main__":
result = unittest.TextTestRunner(verbosity=2).run(suite())
sys.exit(not result.wasSuccessful())
And while running this suite I encounter AttributeError: 'TextTestResult' object has no attribute 'assertIn', and since I dont exactly understand it I cannot fix it ;) If I delete assertIn lines in simpleUsageUnittest.py - then it is working again, but it is of course not what I want to do! Also Asserts in Python 2.7 not working for me example assertIn was not a big help since I am using Python 3.3.5 and Selenium 2.41.0. Can someone explain it to me? Or direct what attributes can I use to save my assert? ;)
Full trace:
C:\Users\zzz\Python\selenium_tutorial>python testTestSuite.py
Traceback (most recent call last):
File "testTestSuite.py", line 14, in <module>
result = unittest.TextTestRunner(verbosity=2).run(suite())
File "C:\Python33\lib\unittest\runner.py", line 168, in run
test(result)
File "C:\Python33\lib\unittest\suite.py", line 67, in __call__
return self.run(*args, **kwds)
File "C:\Python33\lib\unittest\suite.py", line 105, in run
test(result)
File "C:\Users\zzz\Python\selenium_tutorial\simpleUsageUnittest.py", line
18, in test_001_search_in_python_org
self.assertIn("Python", driver.title)
AttributeError: 'TextTestResult' object has no attribute 'assertIn'
SOLUTION
OK, it looks like in my testTestSuite.py, while executing, TextTestRunner treats "self.asserIn" lines in simpleUsageUnittest.py as self == TextTestRunner not as self == TestCase (I dont know if I explain/understand it correctly, but it is how i see it ;)). Here is fixed testTestSuite.py:
import unittest
import simpleUsageUnittest
import sys
def suite():
testSuite = unittest.TestSuite()
testSuite.addTest(simpleUsageUnittest.PythonOrgSearch('test_001_search_in_python_org'))
testSuite.addTest(simpleUsageUnittest.PythonOrgSearch('test_002_goole_and_stack_test_test'))
return testSuite
if __name__ == "__main__":
result = unittest.TextTestRunner(verbosity=2).run(suite())
sys.exit(not result.wasSuccessful())
'setUp' and 'tearDown' are missing because they are called automatically after every 'test'.
SOLUTION
OK, it looks like in my testTestSuite.py, while executing, TextTestRunner treats "self.asserIn" lines in simpleUsageUnittest.py as self == TextTestRunner not as self == TestCase (I dont know if I explain/understand it correctly, but it is how i see it ;)). Here is fixed testTestSuite.py:
import unittest
import simpleUsageUnittest
import sys
def suite():
testSuite = unittest.TestSuite()
testSuite.addTest(simpleUsageUnittest.PythonOrgSearch('test_001_search_in_python_org'))
testSuite.addTest(simpleUsageUnittest.PythonOrgSearch('test_002_goole_and_stack_test_test'))
return testSuite
if __name__ == "__main__":
result = unittest.TextTestRunner(verbosity=2).run(suite())
sys.exit(not result.wasSuccessful())
'setUp' and 'tearDown' are missing because they are called automatically after every 'test'.

Right way to write Unit-Tests in module?

I want to write tests for my main file,calc.py, with unittest in module file, MyTests.py.
Here is my main python file, calc.py:
import myTests
def first(x):
return x**2
def second(x):
return x**3
def main():
one = first(5)
two = second(5)
if __name__ == "__main__":
main()
try:
myTests.unittest.main()
except SystemExit:
pass
And here is my MyTests.py file:
import unittest
import calc
class TestSequenceFunctions(unittest.TestCase):
def setUp(self):
self.testInput = 10
def test_first(self):
output = calc.first(self.testInput)
correct = 100
assert(output == correct)
def test_second(self):
output = calc.second(self.testInput)
correct = 1000
assert(output == correct)
When i run my calc.py, i get the following output:
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK
Why does unittest prints me that "Ran 0 test"?
And what is the right way to write unittest in module?
unittests.main() looks for TestCase instances in the current module. Your module has no such testcases; it only has a myTests global.
Best practice is to run the tests themselves. Add the __main__ section there to the myTests.py file:
import unittest
import calc
class TestSequenceFunctions(unittest.TestCase):
def setUp(self):
self.testInput = 10
def test_first(self):
output = calc.first(self.testInput)
correct = 100
assert(output == correct)
def test_second(self):
output = calc.second(self.testInput)
correct = 1000
assert(output == correct)
if __name__ == '__main__':
unittest.main()
and run python myTests.py instead.
Alternatively, pass in the imported myTests module into unittest.main(). You may want to move the import myTests line down into __main__, because you have a circular import too. That is fine in your case, myTests doesn't use any globals from calc outside of the test cases, but it is better to be explicit about this.
if __name__ == "__main__":
main()
try:
import myTests
myTests.unittest.main(myTests)
except SystemExit:
pass

Categories

Resources