diem_L
diem_L

Reputation: 399

Save unittest results in text file

I'm writing code that tests via unittest if several elements exist on a certain homepage. After the test I want that the results were saved in a text file. But the results in the text file look like this:

......................
.........

------------------------------------------
Ran 12 tests in 22.562s
OK.

But i want that the output looks like this:

test_test1 (HomepageTest.HomePageTest) ... ok
test_test2 (HomepageTest.HomePageTest) ... ok
test_test3 (HomepageTest.HomePageTest) ... ok
etc....
-------------------------------------------------
Ran 12 tests in ...s
OK

This is the code I use for saving the output into a text file:

class SaveTestResults(object):
    def save(self):
       self.f = open(log_file, 'w')
       runner = unittest.TextTestRunner(self.f)
       unittest.main(testRunner = runner, defaultTest ='suite', verbosity = 2)
    
def main():
    STR = SaveTestResults()
    STR.save()

if __name__ == '__main__':
main()

What am I missing or doing wrong?

Upvotes: 3

Views: 6304

Answers (1)

Right leg
Right leg

Reputation: 16700

If the output you wish to save in a file corresponds to what is printed out to the console, you have two main options.

1 - You're using Linux

Then just redirect the output to a file:

python script.py > output.txt

However, the output will not be printed out to the console anymore. If you want to keep the console output, use the tee unix command:

python script.py | tee output.txt

2 - You're using Windows, or you don't want to redirect the whole output to a file

You can achieve more or less the same thing using exclusively Python. You need to set the value of sys.stdout to the file descriptor where you want the output to be written.

import sys
sys.stdout = open("output.txt", 'w')

run_tests()

This will set the output stream stdout to the given file for the whole script. I would suggest defining a decorator instead:

def redirect_to_file(func):

    def decorated(*args, **kwargs):
        actualStdout = sys.stdout
        sys.stdout = open("log.txt", 'a')
        result = func(*args, **kwargs)
        sys.stdout = actualStdout

        return result

    return decorated

Then, just decorate the functions whose you want to write the output to a file:

@redirect_to_file
def run_test():
    ...

If you want a similar behaviour to tee, have a look at this post. The idea is to define a Tee class that holds the two desired streams:

class Tee:
    def __init__(self, stream1, stream2):
        self.stream1 = stream1
        self.stream2 = stream2

    def write(self, data):
        self.stream1.write(data)
        self.stream2.write(data)

    def close(self):
        self.stream1.close()
        self.stream2.close()

Then, set sys.stdout to a Tee instance whose one of the stream is the actual stdout:

tee = Tee(sys.stdout, open("output.txt", 'w'))
sys.stdout = tee

Don't forget to close the tee instance at the end of your script; else, the data written to output.txt will not be saved:

tee.close()

Upvotes: 3

Related Questions