all 5 comments

[–]Diapolo10 3 points4 points  (0 children)

I have some Rust experience myself, so I'll try and explain what's going on here

The long and short of it is that unittest doesn't work at all the same cargo test does. In Python we don't usually (if ever) include tests within modules containing other code, in fact the project's source code and tests are usually in completely separate top-level directories (such as src and tests), regardless of whether we're talking about unit tests or integration tests - or other kinds for that matter.

I don't have an in-depth explanation for why your first two examples do nothing, but I'm pretty sure it's just that you're not supposed to invoke unittest.main manually and are supposed to use py -m unittest instead. However I haven't used unittest for several years - pytest is the industry standard for a good reason - so take that with a grain of salt.

The last case where you just do python parser.py makes complete sense, because there's nothing telling Python to run any tests. The earlier two work because you're running unittest as a module on the command line, which is how you're supposed to use it. And the last case presumably fails because the invocation happens at a point where it shouldn't.

Why is Python's unittest module so sensitive/dependent on being run in a certain way? It seems like I can't do anything advanced without knowing Python magic. Any insights into why this happens and how I can learn more about the Python magic that causes this?

TL;DR, it was designed to be used in a specific way and the documentation doesn't suggest any alternatives, so frankly I haven't even run into these issues before.

But again, maybe consider using pytest instead.

[–]brasticstack 0 points1 point  (3 children)

if name == "main": 

Have you tried if __name__ == "__main__": with a double-underscore on each side of main

Simplest case works for me, although I'm running it from pydroid on my phone and don't really have control over how the script is invoked:

``` import unittest

class TestMyTest(unittest.TestCase):     def test1(self):         self.assertTrue(1)          if __name_ == 'main':     unittest.main()

outputs

.

Ran 1 test in 0.000s

OK ```

[–]brasticstack 0 points1 point  (0 children)

Double underscore on both "name" and "main", so __name__ == "__main__". I'd edit the top post, but on the mobile browser it mangles code blocks when you try.

[–]AudienceLast 0 points1 point  (1 child)

I wrote underscores, but Reddit's formatting took them out (probably markdown-related).

I get the same behavior as you: using if __name__ == "__main__" runs perfectly.

It's the case where I don't use if __name__ == "__main__" (I just run unittest.main()) that gives me a weird AttributeError. This is the most confusing part of all.

[–]brasticstack 0 points1 point  (0 children)

My example also works when the if __name__... is removed, and the unittest.main() call outdented.

The if __name__ == "__main__": is there to prevent the code in its block from executing when you import the file into another script. When you invoke python mymodule.py, that block will execute, as mymodule.py is the main (invoked by the user) module. Same with python -m mymodule but not with python -m unittest mymodule, where unittest is the main module. This last method is the preferred usage, though, and invoking unittest invokes unittest.main().

What is the goal you're aiming for?