【问题标题】:Python unittest print logging works on Linux but not on WindowsPython unittest 打印日志在 Linux 上工作,但在 Windows 上不工作
【发布时间】:2014-01-25 15:35:16
【问题描述】:

我正在尝试编写一个单元测试,它将标准输出和标准错误重定向到 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()

【问题讨论】:

    标签: python windows unittest++


    【解决方案1】:

    在 Windows 上你 can't reassign sys.stdout to redirect output when a script is started via a Windows file association 在 Windows 上存在问题。您可以尝试应该修复它的Windows hotfix。或者您应该能够显式调用 python yourscript.py 来解决它。

    【讨论】:

      【解决方案2】:

      这可能不是最好的方法,但它确实有效 (at least on my machine):

      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"
      

      运行它会产生:

      stdout.txt

      some output
      some other cool output
      

      stderr.txt

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

      os.dup(fd)

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

      os.dup2(fd, fd2)

      os.dup2函数将文件描述符从fd复制到fd2,并关闭fd2的文件描述符。所以,在dup2 调用之后,stdout 现在指向f 文件描述符,同样stderr 现在指向g 文件描述符(并且因为dup2 关闭了第二个文件描述符,所以只有stdoutstderr 的单个文件描述符,因为对 dup 的调用生成了副本。

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

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

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

      [编辑]

      如果不是太多工作,我建议不要使用打印,而是使用logging

      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))
      

      【讨论】:

      • 我尝试了你的代码,如果我没有将它与 unittest 一起使用,它在 Windows 上运行良好。但是当我将它与 unittest 一起使用时,结果相同,它会将任何内容写入日志文件。 :-(
      • import os, sys, unittest LOGDIR = r"\\windows\somenetwork\drive" STDOUT_FD = os.dup(sys.stdout.fileno()) STDERR_FD = os.dup(sys.stderr. fileno()) class MyTest(unittest.TestCase): ... if name == 'main': with open(LOGDIR+'\stdout.txt', 'w ') as f, open(LOGDIR+'\stderr.txt', 'w') as g: os.dup2(f.fileno(), sys.stdout.fileno()) os.dup2(g.fileno(), sys.stderr.fileno()) # 恢复文件描述符 os.dup2(STDOUT_FD, sys.stdout.fileno()) os.dup2(STDERR_FD, sys.stderr.fileno()) unittest.main()
      • 确保您有# revert the File Descriptors dup2 调用之后 unittest.main()
      • 另外,如果切换打印语句不是太多工作,我建议改用logging 模块。您可以创建记录器并设置流处理程序和各种很酷的东西,而且您不需要切换文件描述符。
      • 非常感谢,因为这对我有用!我将尝试记录器类;但是,日志记录是否可以很好地将单元测试通过/失败和错误记录到文件中?
      猜你喜欢
      • 2014-11-09
      • 1970-01-01
      • 2022-01-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-02
      • 1970-01-01
      相关资源
      最近更新 更多