Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(113)

Side by Side Diff: third_party/WebKit/Tools/Scripts/webkitpy/common/system/logtesting.py

Issue 2372653004: Clean up comments and docstrings in webkitpy.common.system.logtesting. (Closed)
Patch Set: Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org) 1 # Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org)
2 # 2 #
3 # Redistribution and use in source and binary forms, with or without 3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions 4 # modification, are permitted provided that the following conditions
5 # are met: 5 # are met:
6 # 1. Redistributions of source code must retain the above copyright 6 # 1. Redistributions of source code must retain the above copyright
7 # notice, this list of conditions and the following disclaimer. 7 # notice, this list of conditions and the following disclaimer.
8 # 2. Redistributions in binary form must reproduce the above copyright 8 # 2. Redistributions in binary form must reproduce the above copyright
9 # notice, this list of conditions and the following disclaimer in the 9 # notice, this list of conditions and the following disclaimer in the
10 # documentation and/or other materials provided with the distribution. 10 # documentation and/or other materials provided with the distribution.
(...skipping 17 matching lines...) Expand all
28 Inherit from the LoggingTestCase class for basic testing needs. For 28 Inherit from the LoggingTestCase class for basic testing needs. For
29 more advanced needs (e.g. unit-testing methods that configure logging), 29 more advanced needs (e.g. unit-testing methods that configure logging),
30 see the TestLogStream class, and perhaps also the LogTesting class. 30 see the TestLogStream class, and perhaps also the LogTesting class.
31 """ 31 """
32 32
33 import logging 33 import logging
34 import unittest 34 import unittest
35 35
36 36
37 class TestLogStream(object): 37 class TestLogStream(object):
38
39 """Represents a file-like object for unit-testing logging. 38 """Represents a file-like object for unit-testing logging.
40 39
41 This is meant for passing to the logging.StreamHandler constructor. 40 This is meant for passing to the logging.StreamHandler constructor.
42 Log messages captured by instances of this object can be tested 41 Log messages captured by instances of this object can be tested
43 using self.assertMessages() below. 42 using self.assertMessages() below.
44 """ 43 """
45 44
46 def __init__(self, test_case): 45 def __init__(self, test_case):
47 """Create an instance. 46 """Creates an instance.
48 47
49 Args: 48 Args:
50 test_case: A unittest.TestCase instance. 49 test_case: A unittest.TestCase instance.
51 """ 50 """
52 self._test_case = test_case 51 self._test_case = test_case
53 self.messages = [] 52 self.messages = [] # A list of log messages written to the stream.
54 """A list of log messages written to the stream."""
55 53
56 # Python documentation says that any object passed to the StreamHandler 54 # Python documentation says that any object passed to the StreamHandler
57 # constructor should support write() and flush(): 55 # constructor should support write() and flush().
58 # 56 #
59 # http://docs.python.org/library/logging.html#module-logging.handlers 57 # http://docs.python.org/library/logging.html#module-logging.handlers
60 58
61 def write(self, message): 59 def write(self, message):
62 self.messages.append(message) 60 self.messages.append(message)
63 61
64 def flush(self): 62 def flush(self):
65 pass 63 pass
66 64
67 def assertMessages(self, messages): 65 def assertMessages(self, messages):
68 """Assert that the given messages match the logged messages. 66 """Asserts that the given messages match the logged messages."""
69
70 messages: A list of log message strings.
71 """
72 self._test_case.assertEqual(messages, self.messages) 67 self._test_case.assertEqual(messages, self.messages)
73 68
74 69
75 class LogTesting(object): 70 class LogTesting(object):
76
77 """Supports end-to-end unit-testing of log messages. 71 """Supports end-to-end unit-testing of log messages.
78 72
79 Sample usage: 73 Sample usage:
80 74
81 class SampleTest(unittest.TestCase): 75 class SampleTest(unittest.TestCase):
82 76
83 def setUp(self): 77 def setUp(self):
84 self._log = LogTesting.setUp(self) # Turn logging on. 78 self._log = LogTesting.setUp(self) # Turn logging on.
85 79
86 def tearDown(self): 80 def tearDown(self):
87 self._log.tearDown() # Turn off and reset logging. 81 self._log.tearDown() # Turn off and reset logging.
88 82
89 def test_logging_in_some_method(self): 83 def test_logging_in_some_method(self):
90 call_some_method() # Contains calls to _log.info(), etc. 84 call_some_method() # Contains calls to _log.info(), etc.
91 85
92 # Check the resulting log messages. 86 # Check the resulting log messages.
93 self._log.assertMessages(["INFO: expected message #1", 87 self._log.assertMessages(["INFO: expected message #1",
94 "WARNING: expected message #2"]) 88 "WARNING: expected message #2"])
95 """ 89 """
96 90
97 def __init__(self, test_stream, handler): 91 def __init__(self, test_stream, handler):
98 """Create an instance. 92 """Creates an instance.
99 93
100 This method should never be called directly. Instances should 94 This method should never be called directly. Instances should
101 instead be created using the static setUp() method. 95 instead be created using the static setUp() method.
102 96
103 Args: 97 Args:
104 test_stream: A TestLogStream instance. 98 test_stream: A TestLogStream instance.
105 handler: The handler added to the logger. 99 handler: The handler added to the logger.
106 """ 100 """
107 self._test_stream = test_stream 101 self._test_stream = test_stream
108 self._handler = handler 102 self._handler = handler
109 103
110 @staticmethod 104 @staticmethod
111 def _getLogger(): 105 def _getLogger():
112 """Return the logger being tested.""" 106 """Returns the logger being tested."""
113 # It is possible we might want to return something other than 107 # It is possible we might want to return something other than
114 # the root logger in some special situation. For now, the 108 # the root logger in some special situation. For now, the
115 # root logger seems to suffice. 109 # root logger seems to suffice.
116 return logging.getLogger() 110 return logging.getLogger()
117 111
118 @staticmethod 112 @staticmethod
119 def setUp(test_case, logging_level=logging.INFO): 113 def setUp(test_case, logging_level=logging.INFO):
120 """Configure logging for unit testing. 114 """Configures logging for unit testing.
121 115
122 Configures the root logger to log to a testing log stream. 116 Configures the root logger to log to a testing log stream.
123 Only messages logged at or above the given level are logged 117 Only messages logged at or above the given level are logged
124 to the stream. Messages logged to the stream are formatted 118 to the stream. Messages logged to the stream are formatted
125 in the following way, for example-- 119 in the following way, for example--
126 120
127 "INFO: This is a test log message." 121 "INFO: This is a test log message."
128 122
129 This method should normally be called in the setUp() method 123 This method should normally be called in the setUp() method
130 of a unittest.TestCase. See the docstring of this class 124 of a unittest.TestCase. See the docstring of this class
131 for more details. 125 for more details.
132 126
127 Args:
128 test_case: A unittest.TestCase instance.
129 logging_level: An integer logging level that is the minimum level
130 of log messages you would like to test.
131
133 Returns: 132 Returns:
134 A LogTesting instance. 133 A LogTesting instance.
135
136 Args:
137 test_case: A unittest.TestCase instance.
138 logging_level: An integer logging level that is the minimum level
139 of log messages you would like to test.
140 """ 134 """
141 stream = TestLogStream(test_case) 135 stream = TestLogStream(test_case)
142 handler = logging.StreamHandler(stream) 136 handler = logging.StreamHandler(stream)
143 handler.setLevel(logging_level) 137 handler.setLevel(logging_level)
144 formatter = logging.Formatter("%(levelname)s: %(message)s") 138 formatter = logging.Formatter("%(levelname)s: %(message)s")
145 handler.setFormatter(formatter) 139 handler.setFormatter(formatter)
146 140
147 # Notice that we only change the root logger by adding a handler 141 # Notice that we only change the root logger by adding a handler
148 # to it. In particular, we do not reset its level using 142 # to it. In particular, we do not reset its level using
149 # logger.setLevel(). This ensures that we have not interfered 143 # logger.setLevel(). This ensures that we have not interfered
150 # with how the code being tested may have configured the root 144 # with how the code being tested may have configured the root
151 # logger. 145 # logger.
152 logger = LogTesting._getLogger() 146 logger = LogTesting._getLogger()
153 logger.addHandler(handler) 147 logger.addHandler(handler)
154 148
155 return LogTesting(stream, handler) 149 return LogTesting(stream, handler)
156 150
157 def tearDown(self): 151 def tearDown(self):
158 """Resets logging.""" 152 """Resets logging."""
159 logger = LogTesting._getLogger() 153 logger = LogTesting._getLogger()
160 logger.removeHandler(self._handler) 154 logger.removeHandler(self._handler)
161 155
162 def messages(self): 156 def messages(self):
163 """Return the current list of log messages.""" 157 """Returns the current list of log messages."""
164 return self._test_stream.messages 158 return self._test_stream.messages
165 159
166 # FIXME: Add a clearMessages() method for cases where the caller 160 # FIXME: Add a clearMessages() method for cases where the caller
167 # deliberately doesn't want to assert every message. 161 # deliberately doesn't want to assert every message.
168 162
169 # We clear the log messages after asserting since they are no longer
170 # needed after asserting. This serves two purposes: (1) it simplifies
171 # the calling code when we want to check multiple logging calls in a
172 # single test method, and (2) it lets us check in the tearDown() method
173 # that there are no remaining log messages to be asserted.
174 #
175 # The latter ensures that no extra log messages are getting logged that
176 # the caller might not be aware of or may have forgotten to check for.
177 # This gets us a bit more mileage out of our tests without writing any
178 # additional code.
179 def assertMessages(self, messages): 163 def assertMessages(self, messages):
180 """Assert the current array of log messages, and clear its contents. 164 """Asserts the current array of log messages, and clear its contents.
165
166 We clear the log messages after asserting since they are no longer
167 needed after asserting. This serves two purposes: (1) it simplifies
168 the calling code when we want to check multiple logging calls in a
169 single test method, and (2) it lets us check in the tearDown() method
170 that there are no remaining log messages to be asserted.
171
172 The latter ensures that no extra log messages are getting logged that
173 the caller might not be aware of or may have forgotten to check for.
174 This gets us a bit more mileage out of our tests without writing any
175 additional code.
176
177 We want to clear the array of messages even in the case of
178 an Exception (e.g. an AssertionError). Otherwise, another
179 AssertionError can occur in the tearDown() because the
180 array might not have gotten emptied.
181 181
182 Args: 182 Args:
183 messages: A list of log message strings. 183 messages: A list of log message strings.
184 """ 184 """
185 try: 185 try:
186 self._test_stream.assertMessages(messages) 186 self._test_stream.assertMessages(messages)
187 finally: 187 finally:
188 # We want to clear the array of messages even in the case of
189 # an Exception (e.g. an AssertionError). Otherwise, another
190 # AssertionError can occur in the tearDown() because the
191 # array might not have gotten emptied.
192 self._test_stream.messages = [] 188 self._test_stream.messages = []
193 189
194 190
195 # This class needs to inherit from unittest.TestCase. Otherwise, the
196 # setUp() and tearDown() methods will not get fired for test case classes
197 # that inherit from this class -- even if the class inherits from *both*
198 # unittest.TestCase and LoggingTestCase.
199 #
200 # FIXME: Rename this class to LoggingTestCaseBase to be sure that
201 # the unittest module does not interpret this class as a unittest
202 # test case itself.
203 class LoggingTestCase(unittest.TestCase): 191 class LoggingTestCase(unittest.TestCase):
204 192
205 """Supports end-to-end unit-testing of log messages. 193 """Supports end-to-end unit-testing of log messages.
206 194
207 Sample usage: 195 This class needs to inherit from unittest.TestCase. Otherwise, the
196 setUp() and tearDown() methods will not get fired for test case classes
197 that inherit from this class -- even if the class inherits from *both*
198 unittest.TestCase and LoggingTestCase.
208 199
209 class SampleTest(LoggingTestCase): 200 Sample usage:
210 201
211 def test_logging_in_some_method(self): 202 class SampleTest(LoggingTestCase):
212 call_some_method() # Contains calls to _log.info(), etc.
213 203
214 # Check the resulting log messages. 204 def test_logging_in_some_method(self):
215 self.assertLog(["INFO: expected message #1", 205 call_some_method() # Contains calls to _log.info(), etc.
216 "WARNING: expected message #2"]) 206
207 # Check the resulting log messages.
208 self.assertLog(["INFO: expected message #1",
209 "WARNING: expected message #2"])
217 """ 210 """
218 211
219 def setUp(self): 212 def setUp(self):
220 self._log = LogTesting.setUp(self) 213 self._log = LogTesting.setUp(self)
221 214
222 def tearDown(self): 215 def tearDown(self):
223 self._log.tearDown() 216 self._log.tearDown()
224 217
225 def logMessages(self): 218 def logMessages(self):
226 """Return the current list of log messages.""" 219 """Return the current list of log messages."""
227 return self._log.messages() 220 return self._log.messages()
228 221
229 # FIXME: Add a clearMessages() method for cases where the caller 222 # FIXME: Add a clearMessages() method for cases where the caller
230 # deliberately doesn't want to assert every message. 223 # deliberately doesn't want to assert every message.
231 224
232 # See the code comments preceding LogTesting.assertMessages() for 225 # See the docstring for LogTesting.assertMessages() for an explanation
233 # an explanation of why we clear the array of messages after 226 # of why we clear the array of messages after asserting its contents.
234 # asserting its contents.
235 def assertLog(self, messages): 227 def assertLog(self, messages):
236 """Assert the current array of log messages, and clear its contents. 228 """Asserts the current array of log messages, and clear its contents."""
237
238 Args:
239 messages: A list of log message strings.
240 """
241 self._log.assertMessages(messages) 229 self._log.assertMessages(messages)
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698