0

I am new to pytest and testing. I have a simple program like below say hi.py

def foo():
   print('hello world')

def bar():
   print('hello python')

if __name__ == "__main__":
   foo()
   bar()

I can run the above program like

python3 hi.py

I have a couple of test cases in test_hi.py like below

import pytest

def test_foo()
   pass

def test_bar()
   pass

To increase code coverage, I also want to test it as python3 hi.py i.e. if __name__==__main__: way. I dont know how will I do it using a test case from test_hi.py. Please help. Thanks.

I am testing the module using pytest

python -m pytest --cov=hi.py
Dr. Mian
  • 3,334
  • 10
  • 45
  • 69
  • The lines in the `if __name__ == "__main__":` block can't be accessed by importing, that's pretty much the point. To run them, you have to actually run the whole program, not just tests. If there's logic in there you find you'd like to test then extract it to a function that you *can* import and exercise, but in this case it's trivial. – jonrsharpe Jan 06 '21 at 08:44
  • you can look at some plugins like https://pypi.org/project/pytest-console-scripts/ or https://pypi.org/project/pytest-click/ for applications that use Click for CLI. That is if I understand your question right. – buran Jan 06 '21 at 08:48
  • I realised my question is a repetition of https://stackoverflow.com/questions/5850268/how-to-test-or-mock-if-name-main-contents Though I am not sure which one to pick or should I exempt from coverage – Dr. Mian Jan 06 '21 at 08:51
  • 1
    You can write an integration test that executes e.g. `runpy.run_path("hi.py", run_name="__main__")` and verifies the behaviour of the script. However, for simple main blocks it's easier just to ignore coverage with `pragma: no cover`. If you have complex main blocks, they should be refactored into a single function `def main(): ...` and tested separately by invoking `main()`. – hoefling Jan 06 '21 at 11:36

2 Answers2

1

Okay so one solution I found for my problem is to exempt that if statement and achieve 100% coverage. To do that I have to add # pragma: no cover after if statement like below.

if __name__ == "__main__":      # pragma: no cover
   foo()
   bar()

The comment will tell pytest to skip the if statement and when you running the following command I can get 100% coverage

python -m pytest --cov=project

However, it is skipping the statements and I would like to cover it instead of skipping it.

Dr. Mian
  • 3,334
  • 10
  • 45
  • 69
0

My theory for code coverage is that you must have 100% coverage. Except where you can't, and then you must have 0% coverage.

You should split your source files into two different folders. One folder is covered by tests and achieves 100%, the files in the other folder are never tested and has 0% coverage.

An example of a zero coverage file is:

from hi import foo, bar

if __name__ == "__main__":
   foo()
   bar()
quamrana
  • 37,849
  • 12
  • 53
  • 71
  • Thanks, in the above case I have given one file for demonstration. Basically I am checking coverage for the whole project. If I split them into two and do the coverage on project level, I will still get 75% coverage. – Dr. Mian Jan 06 '21 at 09:33
  • My theory is for a whole project with multiple files. You move the covered code into files in one folder and leave the uncovered code in files in the alternate folder. You can have `hi.py` 100% covered if you move the `if __name ...` into a different file, like my example above. – quamrana Jan 06 '21 at 09:46
  • Okay, but I guess there is also a command/flag to exclude the statements from coverage criteria. Do you know of any? This way the code can stay intact and coverage of 100%. – Dr. Mian Jan 06 '21 at 10:06
  • Most coverage tools have special comments to add to lines to make the tool ignore that line. – quamrana Jan 06 '21 at 12:31