Python unittest call confusion - python

I have written a unittest of a program MachineSettings_test.py of mine of the following form:
import unittest
import MachineSettings as MS
class TestMachineSettings(unittest.TestCase):
def setUp(self):
[...]
def testStringRepresentation(self):
[...]
def testCasDict(self):
[...]
if __name__=="__main__":
unittest.main()
I am a little bit confused by the following fact:
If I run
python -m unittest -v MachineSettings_test
I get as output
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK
i.e. Python does not recognize the tests inside the unittesting module.
But if I just run
python MachineSettings_test.py
Everything works fine and I get as output
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
This is confusing to me and I could not find any similar question here yet, so I posted it.
The version of Python that I am (forced to be) using is 2.6, but I could not find anything in the documentation that makes this case to be special.
Anyone an idea?
Thanks

From the documentation:
Changed in version 2.7: In earlier versions it was only possible to run individual test methods and not modules or classes.
And you're trying to run tests for whole modules with python 2.6.
Apparently you can't even run from individual test methods with -m unittest in python 2.6. See this question for details.
You might wanna try nose or nose2.

Related

Coverage "No source for code" with pytest

I am trying to measure code coverage by my pytest tests. I tried following the quick start guide of coverage (https://coverage.readthedocs.io/en/6.4.1/)
When I run my test with the following command, everything seems fine
coverage run -m pytest tests/
===================================== test session starts ======================================
platform linux -- Python 3.10.4, pytest-7.1.2, pluggy-1.0.0
rootdir: /home/arnaud/Documents/Github/gotcha
collected 4 items
tests/preprocessing/test_preprocessing.py .... [100%]
====================================== 4 passed in 0.30s =======================================
However, when I try to access the report with either of those commands,
coverage report
coverage html
I get the following message:
No source for code: '<project_directory>/config-3.py'.
I did not find an appropriate solution to this problem so far
It is possible to ignore errors using the command
coverage html -i
which solved my issue
This issue is usually caused by older coverage result files, so you can either:
remove the old coverage results files or...
run coverage command with -i flag in order to ignore the errors - you can read more about that in coverage official docs: https://coverage.readthedocs.io/en/6.4.1/cmd.html#reporting
Another possible solution is to specify the source attribute. In my case, rather than the whole project (source = .), I specified the actual source folder (e.g. src). This can either be done on the commandline:
coverage run --source=src
or include it in your .coveragerc file:
[run]
source = src
...
I was getting this same issue because of a specific library I was importing*, but I never figured out why that library affected coverage, and others didn't.
Though this might just be a workaround, it makes sense to just check your source folder, and ignoring all errors (with -i) isn't much better.
* The library uses opencv-python-headless, which I think has the root cause of this issue.

How pylint-pytest throws F6401 Can-enumerate-pytest-fixtures

Can you explain the prompt 'F6401' when I run pylint pylint-pytest plugin cannot enumerate and collect pytest fixtures. Please run `pytest --fixtures --collect-only path/to/current/module.py` and resolve any potential syntax error or package dependency issues (Can-enumerate-pytest-fixtures) is the reason?
I would like to know how it works, or why it appears, and sometimes has different outputs. The same code, sometimes two, sometimes more. I was depressed.
I did run pytest --fixtures --collect-only without any unusual hints and my tests were normal.
Description:
After I fine-tune my existing code, including running pylint, pytest, and isort, everything works. I added a new package executor with three modules, one is the abstract module of base.py, two are corresponding to different implementation modules(local.py, docker.py).
Then I run isort, and pylint works fine
Then I import the base class and two implementation classes in the module's __init__.py file, and add a factory method.
When I run pylint again, the input tells me that some of the test modules have problems with F6401.
Again, I want to emphasize that everything was fine until I added this module. But now I just added the source code of this module, this exception will appear.
What makes it even more confusing to me is that the module I'm prompted doesn't include any fixtures. I ran pylint again and found that F6401 has more test modules (several times more than last time).
I've been using PyLint for a new project to check for a mode-by-module migration, and when I migrate to this module, I can't continue.
OS env
python 3.7
os: Deepin(base Debian)
IDE: Pycharm
Package versions
pylint 3.0.0a3
pylint-pytest 1.1.2
pyparsing 2.4.7
pytest 6.2.3
pytest-asyncio 0.14.0
pytest-cov 2.11.1
pytest-mock 3.5.1
ISSUE about this question.
After debugging the source code, I found out that the cause of my problems was an error in pylint-pytest when running pytest to collect fixtures from source code, and then pylint-pytest passed the error to PyLint.
My source code had a type annotation error that caused pytest to look for a fixture from that module that was wrong, and the error was passed to pylint. But why there is a different output is not clear to me.
From debugging the source code, we know that pylint-pytest registers itself with pylint, and when pylint checks all files, it passes the files to pylint-pytest's FixtureChecker.
https://github.com/reverbc/pylint-pytest/blob/62676386f80989cc0373d77bc5dc74acc635fd7a/pylint_pytest/checkers/fixture.py#L92-L142
The visit_module method in the FixtureChecker passes the file to pytest, running pytest <module_file> --fixtures --collect-only, At the same time load the FixtureCollector plug-in into pytest.
https://github.com/reverbc/pylint-pytest/blob/62676386f80989cc0373d77bc5dc74acc635fd7a/pylint_pytest/checkers/fixture.py#L125-L131
In pytest_collectreport , if an error is reported by pytest, it is logged and the error information is passed to pytest.
https://github.com/reverbc/pylint-pytest/blob/62676386f80989cc0373d77bc5dc74acc635fd7a/pylint_pytest/checkers/fixture.py#L24-L34
I don't think this logic makes sense. Pytest should only collect fixtures from the test modules, and instead of collecting fixtures from all modules, Pylint-Pytest should filter out the source code when PyLint checks.
At this point, my doubts have disappeared. Thanks.

Python Unittest: AttributeError: no attribute 'assertTrue' when running on Linux

I am running some very simple unit tests in Python, and found that the assertTrue() function won't work, while in the same testcase the assertEqual() is working fine.
To simplify the issue, I have minimized the code into the following:
import unittest
class easyTest (unittest.TestCase):
def setUp(self):
pass
def test_true(self):
self.assertTrue(True)
if __name__ == "__main__":
unittest.main()
This batch of codes runs perfectly on my Windows laptop, but returns
AttributeError: easyTest instance has no attribute 'assertTrue'
when I try to run it on Linux.
On both laptops, I am using python 2.7.6, on IDE pyCharm Community Edition 2017.1.4. My Linux laptop is running Ubuntu 14.04.1
I have found a very similar question here:
AttributeError: TestSwitch instance has no attribute 'assertTrue'
And since it seems that nobody is answering the question, I am asking here again, hoping for some prominent answers.
According to your comment, the unittest version you are using is (the long deprecated) stand-alone PyUnit 1.4.1 package. As the package's homepage mentions:
Unless you're stuck in the year 2000, PyUnit is in your Python standard library as module unittest.
And indeed, unittest was added to the stdlib in Python 2.1.
IOW, unless you're stuck with an antediluvian legacy code base (using Python < 2.1 !), you should just uninstall PyUnit and your problem will be solved.
Is it possible that you have a second unittest module or package in your python path?
If you created a unittest.py file or a unittest directory containing an __init__.py file, python could find that before it finds the normal module in the standard python library.
Naming a local module or package unittest is the equivalent of naming a local variable list or dict or map; you are masking the built-in name with a local redefinition.
Rename that module or package to something else to fix this.

Code coverage does not cover dynamically imported packages/modules

I am using the following command to run tests:
nosetests --with-coverage --cover-html --cover-package mypackage
I would like the coverage report to be updated, even if a developer adds new, untested, code to the package.
For example, imagine a developer adds a new module to the package but forgets to write tests for it. Since the tests may not import the new module, the code coverage may not reflect the uncovered code. Obviously this is something which could be prevented at the code review stage but it would be great to catch it even earlier.
My solution was to write a simple test which dynamically imports all modules under the top-level package. I used the following code snippet to do this:
import os
import pkgutil
for loader, name, is_pkg in pkgutil.walk_packages([pkg_dirname]):
mod = loader.find_module(name).load_module(name)
Dynamically importing sub-packages and sub-modules like this does not get picked up by the code coverage plugin in nose.
Can anyone suggest a better way to achieve this type of thing?
The problem seems to be the method for dynamically importing all packages/modules under the top-level package.
Using the method defined here seems to work. The key difference being the use of importlib instead of pkgutil. However, importlib was introduced in python 2.7 and 3.1 so this solution is not appropriate for older versions of python.
I have updated the original code snippet to use __import__ instead of the ImpLoader.load_module method. This also seems to do the trick.
import os
import pkgutil
for loader, name, is_pkg in pkgutil.walk_packages([pkg_dirname]):
mod = loader.find_module(name)
__import__(mod.fullname)

How to use nose with IronPython?

I installed nose using the 'setup.py install' on the command line , I am able to run 'nosetests' and any python file matching testMatch regular expression is picked up and tests are automated in the %python home%\Scripts directory. Now I want nose to work with my iron Python files , how do I install nose on the %Iron Python home% directory ? i noticed my Iron Python Home directory does not even have a Scripts folder.
If i try running 'nosetests' with iron python code , it throws all sorts of exception
for eg. no module named clr.
Is anybody using nose with iron python ? if yes , please guide me. I have been struggling with this since an entire day,
currently my only workaround has been adding the following in my IronPython code:
import nose
nose.main(argv=['<arguments>'])
is this is the only way to go about using nose in iron python files ?
if there is no other way , then I wanted to know how to use the several plugins that nose has ? especially the coverage plugin ? i installed it for python2.6 , but how to make it work for ironpython ?
The reason I am asking is because with python , it gets easy to use the plugins just by calling the command line , but with IronPython I don't know how to make it work.
Your solution is actually all nosetests does:
#!/usr/bin/env python
from nose import main
if __name__ == '__main__':
main()
You'll want to make sure you add your system's Python lib to the path for it to find the nose extensions:
>>>import sys
>>>sys.path.append(r'C:\Python26\lib')
And you'll need to make sure you're executing your script with ipy.exe and not your system's Python executable.
I've been trying to run the sqlalchemy test suite, which uses nose and a plugin. So, this may be useful if anyone is trying to run nose on ironpython with plugins.
this tends not to work transparently on ipy, because setuptools doesn't quite work on ironpython.
after a bit of diggin, i found the nose init.py instructions for registering a plugin manually - essentially, import the plugin class (which subclasses nose.plugins.Plugin), and add it to the call to main().
here's what my script ended up looking like:
import sys, os
#import ironclad #not needed. i think.
sys.path.append(r'C:\Python26\lib')
#now load Jeff Hardys sqlite dll which is in sqlite folder (sqlite not supported on ipy)
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)),'sqlite'))
import clr
clr.AddReference('IronPython.SQLite')
#load plugin
from sqlalchemy.test.noseplugin import NoseSQLAlchemy
from nose import main
if __name__ == '__main__':
main(addplugins=[NoseSQLAlchemy()])
Hope this helps someone!

Categories