0

我正在尝试编写一个单元测试,它将标准输出和标准错误重定向到 Windows 网络驱动器上写入的文件。出于某种原因,相同的脚本(只有 diff. 是目录路径)适用于 Linux,但不适用于 Windows。在 Windows 上运行时,不会将任何内容写入日志文件。

这是 Windows 上的脚本,没有写入任何内容:

import sys
import unittest

LOGDIR = r"\\windows\somenetwork\somedrive"
LOG1 = open(LOGDIR+'\myStdOut.txt', 'w')
LOG2 = open(LOGDIR+'\myStdErr.txt', 'w')

class MyTest(unittest.TestCase):

currentResult = None # holds last result object passed to run method

def setUp(self):
    pass

def tearDown(self):
    ok = self.currentResult.wasSuccessful()
    errors = self.currentResult.errors
    failures = self.currentResult.failures
    print ' All tests passed so far!' if ok else \
            ' %d errors and %d failures so far' % \
            (len(errors), len(failures))

def run(self, result=None):
    self.currentResult = result # remember result for use in tearDown
    unittest.TestCase.run(self, result) # call superclass run method

def test_onePlusOneEqualsTwo(self):
    self.assertTrue(1 + 1 == 2) # succeeds

def test_onePlusOneEqualsThree(self):
    self.assertTrue(1 + 1 == 3) # fails

def test_onePlusNoneIsNone(self):
    self.assertTrue(1 + None is None) # raises TypeError

if __name__ == '__main__':
    sys.stdout = LOG1 
    sys.stderr = LOG2
    unittest.main()
    LOG1.close()
    LOG2.close()

在 Linux 上运行的相同脚本可以工作或至少会写入文件:

import sys
import unittest

LOGDIR = r"/tmp"
LOG1 = open(LOGDIR+'/myStdOut.txt', 'w')
LOG2 = open(LOGDIR+'/myStdErr.txt', 'w')

MyTestLinux 类(unittest.TestCase):

currentResult = None # holds last result object passed to run method

def setUp(self):
    pass

def tearDown(self):
    ok = self.currentResult.wasSuccessful()
    errors = self.currentResult.errors
    failures = self.currentResult.failures
    print ' All tests passed so far!' if ok else \
            ' %d errors and %d failures so far' % \
            (len(errors), len(failures))

def run(self, result=None):
    self.currentResult = result # remember result for use in tearDown
    unittest.TestCase.run(self, result) # call superclass run method

def test_onePlusOneEqualsTwo(self):
    self.assertTrue(1 + 1 == 2) # succeeds

def test_onePlusOneEqualsThree(self):
    self.assertTrue(1 + 1 == 3) # fails

def test_onePlusNoneIsNone(self):
    self.assertTrue(1 + None is None) # raises TypeError

if __name__ == '__main__':
    sys.stdout = LOG1 
    sys.stderr = LOG2
    unittest.main()
    LOG1.close()
    LOG2.close()
4

2 回答 2

2

存在一个问题,在 Windows 上,当通过 Windows 上的 Windows 文件关联启动脚本时,您无法重新分配 sys.stdout 以重定向输出。您可以尝试应该修复它的Windows 修补程序。或者您应该能够显式调用python yourscript.py来解决它。

于 2014-01-07T19:51:05.880 回答
1

这可能不是最好的方法,但它有效(至少在我的机器上):

import os
import sys
import unittest

STDOUT_FD = os.dup(sys.stdout.fileno())
STDERR_FD = os.dup(sys.stderr.fileno())

with open('stdout.txt', 'w') as f, open('stderr.txt', 'w') as g:
    os.dup2(f.fileno(), sys.stdout.fileno())
    os.dup2(g.fileno(), sys.stderr.fileno())


class MyTest(unittest.TestCase):
    def test_print(self):
        print 'some output'
        self.assertEqual('', '')

    def test_some_moar(self):
        print 'some other cool output'
        self.assertTrue(True)

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

print 'I am printing to stdout.txt'
print >> sys.stderr, 'I am printing to stderr.txt'

# revert the File Descriptors
os.dup2(STDOUT_FD, sys.stdout.fileno())
os.dup2(STDERR_FD, sys.stderr.fileno())

print "Yay! Back to printing in the console"

运行它会产生:

标准输出文件

some output
some other cool output

标准错误文件

..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

os.dup(fd)

os.dup函数创建文件描述符的副本并返回该复制文件描述符的整数。因此,在前两次dup调用之后,有两个文件描述符指向stdout和两个指向stderr.

os.dup2(fd, fd2)

os.dup2函数将文件描述符从 复制fdfd2并关闭 的文件描述符fd2。因此,在dup2调用之后,stdout现在指向f文件描述符,同样stderr现在指向g文件描述符(并且由于dup2关闭了第二个文件描述符,因此两者只有一个文件描述符,stdout并且stderr由于对 的调用产生了副本dup)。

随心所欲地打印所有内容。

最后,最后两个dup2调用使用复制的文件描述符(因此 stdout 和 stderr 指向您期望的位置)恢复文件描述符,这也会关闭文件fg.

根据dup2文档,这适用于 Linux 和 Windows。

[编辑]

如果工作量不大,我建议不要使用 printslogging而是使用:

import logging
import unittest


class MyTest(unittest.TestCase):
    def test_print(self):
        logging.info('some output')
        self.assertEqual('', '')

    def test_some_moar(self):
        logging.info('some other cool output')
        self.assertTrue(True)

if __name__ == '__main__':
    logging.basicConfig(level=logging.INFO)
    # get the default logger
    logger = logging.getLogger()
    # add a file handler
    logger.addHandler(logging.FileHandler('stdout.txt', mode='w'))
    # set up a stream for all stderr output
    stderr_file = open('stderr.txt', 'w')
    # attach that stream to the testRunner
    unittest.main(testRunner=unittest.TextTestRunner(stream=stderr_file))
于 2014-01-07T20:34:08.767 回答