0
votes

I have a python script in which I wrote some unit tests and I am using selenium.

I want to extract the whole output of the console (not only my prints but also the unit test related results), so that I can import them later in my test management tool.

Output

Here is my code:

import unittest
from selenium import webdriver
import json
import requests
import sys


class TestUbuntuHomepage(unittest.TestCase):
    global strs

    strs = []

    def setUp(self):
        sys.stdout = open("C:\\Users\\Marialena\\Downloads\\out2.log", 'wt')

        self.driver = webdriver.Firefox(executable_path="C:\\Users\\Marialena\\Downloads\\selenium-drivers\\geckodriver")


    def testTitle(self):
        self.driver.get('http://www.ubuntu.com/')

        if self.assertIn('Ubuntu', self.driver.title):
            strs.append('test'})


    def tearDown(self):
        self.driver.quit()


if __name__ == '__main__':
    unittest.main(verbosity=2)

Using sys.stdout = open("C:\\Users\\Marialena\\Downloads\\out2.log", 'wt') I get in the file everything I have printed and I also get this exception:

Traceback (most recent call last): File "C:\Program Files\JetBrains\PyCharm\PyCharm Community Edition 2017.3.3\helpers\pycharm_jb_unittest_runner.py", line 35, in main(argv=args, module=None, testRunner=unittestpy.TeamcityTestRunner, buffer=not JB_DISABLE_BUFFERING) File "C:\Users\Marialena\AppData\Local\Programs\Python\Python36-32\Lib\unittest\main.py", line 95, in init self.runTests() File "C:\Users\Marialena\AppData\Local\Programs\Python\Python36-32\Lib\unittest\main.py", line 256, in runTests self.result = testRunner.run(self.test) File "C:\Program Files\JetBrains\PyCharm\PyCharm Community Edition 2017.3.3\helpers\pycharm\teamcity\unittestpy.py", line 304, in run return super(TeamcityTestRunner, self).run(test) File "C:\Users\Marialena\AppData\Local\Programs\Python\Python36-32\Lib\unittest\runner.py", line 176, in run test(result) File "C:\Users\Marialena\AppData\Local\Programs\Python\Python36-32\Lib\unittest\suite.py", line 84, in call return self.run(*args, **kwds) File "C:\Users\Marialena\AppData\Local\Programs\Python\Python36-32\Lib\unittest\suite.py", line 122, in run test(result) File "C:\Users\Marialena\AppData\Local\Programs\Python\Python36-32\Lib\unittest\suite.py", line 84, in call return self.run(*args, **kwds) File "C:\Users\Marialena\AppData\Local\Programs\Python\Python36-32\Lib\unittest\suite.py", line 122, in run test(result) File "C:\Users\Marialena\AppData\Local\Programs\Python\Python36-32\Lib\unittest\suite.py", line 84, in call return self.run(*args, **kwds) File "C:\Users\Marialena\AppData\Local\Programs\Python\Python36-32\Lib\unittest\suite.py", line 122, in run test(result) File "C:\Users\Marialena\AppData\Local\Programs\Python\Python36-32\Lib\unittest\case.py", line 653, in call return self.run(*args, **kwds) File "C:\Users\Marialena\AppData\Local\Programs\Python\Python36-32\Lib\unittest\case.py", line 624, in run result.stopTest(self) File "C:\Program Files\JetBrains\PyCharm\PyCharm Community Edition 2017.3.3\helpers\pycharm\teamcity\unittestpy.py", line 260, in stopTest output = sys.stdout.getvalue() AttributeError: '_io.TextIOWrapper' object has no attribute 'getvalue'

Any help with this, please? Thank you.

1
It may be a bug with PyCharm itself: link here. - ely
I would try restoring the original sys.stdout in tearDown... - zvone
@ely I'll have a look if this is a pycharm issue. thank you - Marialena
@zvone I get the same error also in tearDown but thanks - Marialena
@Marialena If you are having "the same error" even after doing self.original_stdout = sys.stdout in setUp and then sys.stdout = self.original_stdout in tearDown, you should probably move the whole stdout handling into each test. It seems that PyCharm already replacing stdout with something it expects to be there after each test is run. - zvone

1 Answers

1
votes

It looks like PyCharm is replacing sys.stdout with its own stream, so when you replace it with a file stream, PyCharm fails to use it.

So, limit your interventions to the scope of one function, to avoid interference with PyCharm.

This is the general idea:

def testTitle(self):
    original_stdout = sys.stdout
    sys.stdout = open("C:\\Users\\Marialena\\Downloads\\out2.log", 'wt')

    # your test code goes here

    sys.stdout = original_stdout

Now, from the outside, it will look like sys.stdout was never modified.

Of course, you'll want to improve on some things:

  • handle exceptions in test - restore stdout in a finally block
  • avoid deleting the file in each test - open the file in append mode
  • avoid having to copy-and-paste this code in each test - make a context manager
@contextmanager
def redirected_stdout(filename):
    original_stdout = sys.stdout
    sys.stdout = open(filename, 'at')
    try:
        yield
    finally:
        sys.stdout = original_stdout

and then:

def testTitle(self):
    with redirected_stdout("C:\\Users\\Marialena\\Downloads\\out2.log"):
        # your test code goes here

Alternatively:

Investigate how PyCharm expects sys.stdout to behave and make your own class which does both: writes to file and provides the API which PyCharm expects.