I'm trying to write a unittest that will redirect stdout and stderr to a file written on a Windows network drive. For some reason, the same script (only diff. is the directory path) works on Linux but not on Windows. When run on Windows, nothing is written to the log file.
Here is the script on Windows and nothing gets written:
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()
The same script run on Linux works or would at least write to the files:
import sys
import unittest
LOGDIR = r"/tmp"
LOG1 = open(LOGDIR+'/myStdOut.txt', 'w')
LOG2 = open(LOGDIR+'/myStdErr.txt', 'w')
class 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()
This may not be the best way to do this, but it works (at least on my machine):
Running this produces:
stdout.txt
stderr.txt
os.dup(fd)
The
os.dup
function creates a copy of the file descriptor and returns the integer of that duplicated file descriptor. So, after the first twodup
calls, there are two file descriptors pointing tostdout
and two pointing tostderr
.os.dup2(fd, fd2)
The
os.dup2
function copies the file descriptor fromfd
tofd2
and closes the file descriptor offd2
. So, after thedup2
calls,stdout
now points to thef
file descriptor and likewisestderr
now points to theg
file descriptor (and becausedup2
closes the second file descriptor, there is only a single file descriptor for bothstdout
andstderr
because of the copies made by the call todup
).Print everything to your heart's content.
At the end, the last two
dup2
calls revert the file descriptors using the copied file descriptors (so stdout and stderr point to where you'd expect) which also closes filesf
andg
.According to the dup2 docs, this works on both Linux and Windows.
[Edit]
If it's not too much work, I would suggest not using prints and use
logging
instead: