ScreenPyHQ / screenpy

Screenplay pattern base for Python automated UI test suites.
MIT License
27 stars 3 forks source link

Investigate if there's a way to improve the debugging experience. #44

Open perrygoy opened 1 year ago

perrygoy commented 1 year ago

Currently when exceptions are raised while an Actor is performing, the user is shown a stack trace right where the exception is raised. That's good! Sometimes.

Usually they want to be up at the attempts_to call that contains the Action that was being performed when they encountered the exception, so they can see what the Actor looked like. See if there's a way to excise certain transitional frames (like the Actor.perform and Actor.attempts_to), or start at a different frame than the most recent one.

bandophahita commented 1 year ago

Building Quietly had me thinking about this...

My initial thoughts are messing with exceptions is trouble. Any python dev is going to expect the stack to give them what it always has. I also agree that as a QA tester, sometimes that stack isn't super helpful, contextually.

Perhaps the info we need should be logged just prior to the exception?

bandophahita commented 1 year ago

We need a good sample test that illustrates this issue.

perrygoy commented 1 year ago

So i'm thinking of three cases here:

Currently, the stack trace that is shown and the place you end up with pytest --pdb are either inside of PyHamcrest or inside of Actor (probably .perform or inside of the Action or Question that failed). You probably want to wind up inside of your test instead. Same with Debug(), you'd probably want to end up in that chain of Actions. In any of these cases, you have to follow the thread of frames back up to the place you want to be.

pytest actually does something pretty spectacular with these, as the --pdb flag drops you directly into the test where the error was raised, rather than in the bowels of pytest. I tried following the code it uses to do that and it looks like it uses its own tracing logic, which is complicated but super cool.

If we could trace the code execution, we might be able to set the latest trace when the Actor does .attempts_to and return the frame just above that to put the user into their test or task or something? I dunno, i'd need to mess around with it to figure it out. All i know is that whenever i use one of the methods above, i'm annoyed that i have to sift through all the deep recesses of our framework and the frameworks we use, while pytest shows us that we can do it better.

I'll see if i can make a quick sample test to show what i mean.

bandophahita commented 1 year ago

I should preface, I can count the number of times I've used pdb directly on one hand. My knowledge on how to use it is limited. I almost exclusively use the debugger in pycharm.

In the initial post, you talk about the stack that occurs when an exception is raised. I had assumed you were talking about the stderr exception stack output. I wasn't think about using pdb at that point. I'm guessing they do not look the same?

perrygoy commented 1 year ago

I am talking about that, too, yes. I believe both of those "issues" (the verbose stacktrace and the inconvenient frame pdb lands in) could be solved in the same manner, but i don't know for sure. They look the same currently in that the same stacktrace that is shown in stderr is the same frame stack that you have to traverse in pdb.

bandophahita commented 1 year ago

If we could trace the code execution, we might be able to set the latest trace when the Actor does .attempts_to and return the frame just above that to put the user into their test or task or something? I dunno, i'd need to mess around with it to figure it out. All i know is that whenever i use one of the methods above, i'm annoyed that i have to sift through all the deep recesses of our framework and the frameworks we use, while pytest shows us that we can do it better.

I agree that putting the breakpoint in the right place is hard. Actions inside of actions, etc will often lead to being down a stack of multiple actor.attempts_to() and someaction.perform_as() deep.

Incorporating something into the Debug() action would be great, but I would advise caution when it comes to any sort of stack evaluation trickery. Especially if it would make trying to step into those areas difficult or impossible during regular debugging.

Oddly enough I ran into similar issues when it came time to getting python logging to print the file and line numbers of beat logging rather than always showing the stdout_adapter. I had to resort to keeping track of modules in the stack to ignore. I imagine something similar would need to be done to accomplish what you're looking for.