0

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.

6
  • It may be a bug with PyCharm itself: link here. Commented Feb 27, 2018 at 16:07
  • I would try restoring the original sys.stdout in tearDown... Commented Feb 27, 2018 at 16:09
  • @ely I'll have a look if this is a pycharm issue. thank you Commented Feb 27, 2018 at 16:15
  • @zvone I get the same error also in tearDown but thanks Commented Feb 27, 2018 at 16:15
  • 1
    @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. Commented Feb 27, 2018 at 16:37

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

thank you very much for your solution, suggestion and your time. However I tried to specify my search to unit test results so i am executing my test using this command: pytest --junitxml junit-results.xml sel-test.py and I am now able to get the output and any errors occurred with this. Not the best solution as I couldn't use it directly from my script but it still works.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.