| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
|
This PR needs a skip-news label. |
Sorry, something went wrong.
There was a problem hiding this comment.
Okay here's our goal - making the unittest easy to understand and easy to write. Ideally, we only need data in our unittest, no logic at all. All the logic should be dealt with in our utility method.
For example, the test would look like
def test_handling_info_message(self):
server_messages = [
{"message": "Some message or other.\n", "type": "info"},
]
stdout, stderr = self.do_test(
server_messages=server_messages,
outgoing_messages=[],
write_success=True, # this could be default
)
self.assertEqual("*** Some message or other.\n", stdout)The test write should not need to know anything about mock, client or socket file.
We need to do something clever with the prompts and completions but the direction should be like this. We should be able to write a test with only input and output in our mind, not all the mock details.
The readline mock piece was specifically difficult to read. I think we should be able to make the unittest itself looks like - I'll press here, let's see the result.
Another suggestion is that we should replace all the blah to something a little bit more meaningful. That would also help understand the test.
I think my major goal is to make it as easy as possible for future developers to come up with their own test when they try to fix a bug. We should hide all the mock details if possible.
Sorry, something went wrong.
I don't think I understand what you're proposing. Your example has a test setup (the server_messages = ...), an execution of the system under test (the self.do_test), and some assertions about the observed behavior of the system under test. Those exactly correspond to the given/when/then structure of all of these tests. Taking one of my tests, chosen mostly at random: def test_handling_pdb_prompts(self):
"""Test responding to pdb's normal prompts."""
# GIVEN
prompts_and_inputs = [
("(Pdb) ", "blah ["),
("... ", "blah ]"),
("(Pdb) ", ""),
("(Pdb) ", "b ["),
("(Pdb) ", "! b ["),
("... ", "b ]"),
]
prompts = [pi[0] for pi in prompts_and_inputs]
inputs = [pi[1] for pi in prompts_and_inputs]
num_prompt_msgs = sum(pi[0] == "(Pdb) " for pi in prompts_and_inputs)
messages = [
{"command_list": ["b"]},
] + [{"prompt": "(Pdb) ", "state": "pdb"}] * num_prompt_msgs
sockfile = MockDebuggerSocket(messages)
client = self.create_pdb_client(sockfile)
# WHEN
with (
unittest.mock.patch("pdb.input", side_effect=inputs) as input_mock,
):
client.cmdloop()
# THEN
expected_outgoing = [
{"reply": "blah [\nblah ]"},
{"reply": ""},
{"reply": "b ["},
{"reply": "!b [\nb ]"},
]
self.assertEqual(sockfile.outgoing, expected_outgoing)
self.assertFalse(client.write_failed)
self.assertEqual(client.state, "pdb")
input_mock.assert_has_calls([unittest.mock.call(p) for p in prompts])How would you prefer this test look? It's got two streams of input being fed to the system under test (the prompt messages coming from the PDB server and the user input on stdin), and it's testing that when the user's input is: "blah [\nblah ]\n\nb [\n! b [\nb ]"
Can you show how you would set up the test to provide that input and make those assertions? |
Sorry, something went wrong.
|
I would expect something like # not sure if message is the perfect variable name but that's irrelevant
messages = [
("server", {"command_list": ["b"]}),
("server", {"prompt": "(Pdb) ", "state": "pdb"}),
("client", {"prompt": "(Pdb) ", "input": "blah ["}),
("client", {"prompt": "... ", "input": "blah ]"}),
("server", {"prompt": "(Pdb) ", "state": "pdb"}),
...
]
self.do_test(messages, expected_outgoing=expected_outgoing, ...)In reality, we actually feed the mock server (sockfile) all the messages and just do the loop. However, this order thing gives us the possibility to check the actual message order, and gives a better idea of what's really going on. Notice that - we don't have to check prompt on the client side for every single test, it could be omitted so the test case would be simpler. # not sure if message is the perfect variable name but that's irrelevant
messages = [
("server", {"command_list": ["b"]}),
("server", {"prompt": "(Pdb) ", "state": "pdb"}),
("client", {"input": "blah ["}),
("client", {"input": "blah ]"}),
("server", {"prompt": "(Pdb) ", "state": "pdb"}),
...
]
self.do_test(messages, expected_outgoing=expected_outgoing, ...)What I want is 0 logic in the test case itself. I can just translate the events I expected to some data structure and I got my test case. |
Sorry, something went wrong.
OK, I've pushed a new commit that does this, please take another look. |
Sorry, something went wrong.
|
No idea what the failure in the tsan test is about, but it seems unrelated to my changes. |
Sorry, something went wrong.
There was a problem hiding this comment.
I think overall, this is very close to what I imagine. We put all the logic in a utility function and we have only data in our unittests. I do have a few comments about the structure and details, but the direction is definitely what I want.
Sorry, something went wrong.
…ests See if this helps to resolve the tsan failures for test_opcache
| Back | FazBrowse Home | New Git URL |
As promised, here are some additional tests for _PdbClient. These exercise all of its features quite well, with the exception of its ability to send interrupts to the remote process. I've left that out for now since that's still a bit in flux due to #132975.
CC: @gaogaotiantian @pablogsal