Python Behave - ConfigError: No steps directory in [] - python

Following the tutorial for setting up behave (https://behave.readthedocs.io/en/latest/tutorial.html), I'm getting a ConfigError: No steps directory in error message.
My file structure:
VS Code/TestingAutomationPOC/
VS Code/TestingAutomationPOC/features/
VS Code/TestingAutomationPOC/features/steps/
VS Code/TestingAutomationPOC/features/steps/tutorial.py
VS Code/TestingAutomationPOC/feature/tutorial.feature
Installed behave (1.2.6) via pip.
Added "python.linting.pylintArgs": ["--load-plugin","pylint_protobuf"] to user settings which fixed my import issue but did not help with this ConfigError.
From tutorial.py:
from behave import *
#given('we have behave installed')
def step_impl(context):
pass
#when('we implement a test')
def step_impl(context):
assert True is not False
#then('behave will test it for us!')
def step_impl(context):
assert context.failed is False
From tutorial.feature:
Feature: showing off behave
Scenario: run a simple test
Given we have behave installed
When we implement a test
Then behave will test it for us!
What am I doing wrong?

You can try the command:
behave **/feature_file_name

Your working directory in VisualStudio is probably not correct.
HINTS:
Print the command-line how behave is executed
Print the current working directory for this execution (cmd-shell: %CD%)
Provide your own python script "my_behave.py" to run behave. It can easily shown/print the diagnostics above.

I faced similar issue. First thing you need to make sure your folder path is correct. Second thing , create steps folder inside your project features folder. now run the behave command with feature file name or without file name, it should work.
├── feature [folder]
│ |── steps [folder]
├── filename.feature [file]

Related

Python unit tests not discovered in VSCode

I've written a python test file called scraping_test.py, with a single test class, using unittest, called TestScrapingUtils
"""Tests for the scraping app"""
import unittest
from bs4 import BeautifulSoup as bs4
from mosque_scraper.management.commands import scraping_utils
from mosque_scraper.selectors import MOSQUE_INFO_ROWS_SELECTOR
class TestScrapingUtils(unittest.TestCase):
"""Test scraping_utils.py """
def setup(self):
"""Setup McSetupface."""
pass
def test_get_keys_from_row(self):
""" Test that we extract the correct keys from the supplied rows."""
test_page_name = "test_page.html"
with open(test_page_name) as test_page_file:
test_mosque = bs4(test_page_file, 'html.parser')
rows = test_mosque.select(MOSQUE_INFO_ROWS_SELECTOR)
field_dict = scraping_utils.get_fields_from_rows(rows)
self.assertDictEqual(field_dict, {})
My settings for unit tests are:
{
"python.unitTest.unittestEnabled": true,
"python.unitTest.unittestArgs": [
"-v",
"-s",
".",
"-p",
"*test.py"
]
}
It looks like it should work, but when I click to run the tests in VSCode it says that no tests were discovered:
No tests discovered, please check the configuration settings for the tests.
How do I make it work?
You have to run it once by using shortcut key shift+ctrl p, and type "Python run all unit tests".
It won't show up in the editor until it was successfully executed at least once or use the discover unit test method.
However one thing catch me many times is that the Python file has to be a valid Python file. The intellisense in VS Code for Python is not complex(compare to Javascript or Typescript), and it won't highlight any syntax error. You can verify that by force it to run all unit test and observe the Python Test Log window.
What caught me is that the __init__.py file must be created in every subdirectory, from the root folder specified with -s option (in the example, the current directory ".") to the subdirectory where the test module is located. Only then was I able to discover tests successfully.
In the question example, both project_dir/ and project_dir/scraping_app/ should contain __init__.py. This is assuming that settings.json is located in project_dir/.vscode and the tests are run from project_dir/ directory.
Edit: Alternatively, use "-s", "./scraping_app/" as the root test directory so you don't have to put __init__.py to project_dir/.
Instead of file name 'scraping_test.py' it shall be 'test_scraping.py'
string shall start from 'test' prefix
I had the same error with a slightly different configuration. (I am posting this here because this is the question that comes up when you search for this error.)
In addition to what was said above, it is also important to not use periods in the test file names (e.g. use module_test.py instead of module.test.py).
You can add the DJANGO_SETTINGS_MODULE variable and django.setup() inside the __init__.py file of tests package.
import os
import django
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'your_app.settings')
django.setup()
In my case, the problem was that my test was importing a module which was reading an environment variable using os.environ['ENV_NAME']. If the variable does not exist, it throws an error. But VS Code does not log anything (or at least I couldn't find it).
So, the reason was that my .env file was NOT in the workspace root. So I had to add "python.envFile": "${workspaceFolder}/path/to/.env" to the settings.json file.
After that, the test was discovered successfully.
Also had this issue.
for me the issue was, make sure there are no errors, and comment out all code in files that rely on pytest, just for the initial load up.
Another issue that causes the unit tests not be discovered is when using a conda environment that contains an explicit dependency on the conda package itself. This happens when the enviroment.yml contains the line:
- conda
Removing this line and creating the environment from scratch makes the unit tests discoverable. I have created a bug report in Github for this: https://github.com/microsoft/vscode-python/issues/19643
(This is my second solution to this issue; I decided to create another answer since this is entirely different from the previous one.)
This is my first time using unittest in vscode. I found that the file names cannot contain spaces and dots. and cannot start with numbers.
for the dots, I guess anything after a dot is considered by the extension by unittest.
for the spaces, I guess they do not use "" to surround the filename.
For me Discovering the unit tests did the trick.
SHIFT+CTRL+P and execute "Python: Discover unit tests"
After running this I get the "Run Test|Debug Test" over each test function.

PyCharm + cProfile + py.test --> pstat snapshot view + call graph are empty

In PyCharm, I set up py.test as the default test runner.
I have a simple test case:
import unittest
import time
def my_function():
time.sleep(0.42)
class MyTestCase(unittest.TestCase):
def test_something(self):
my_function()
Now I run the test by right-clicking the file and choosing Profile 'py.test in test_profile.py'.
I see the test running successfully in the console (it says collected 1 items). However, the Statistics/Call Graph view showing the generated pstat file is empty and says Nothing to show.
I would expect to see profiling information for the test_something and my_function. What am I doing wrong?
Edit 1:
If I change the name of the file to something which does not start with test_, remove the unittest.TestCase and insert a __main__ method calling my_function, I can finally run cProfile without py.test and I see results.
However, I am working on a large project with tons of tests. I would like to directly profile these tests instead of writing extra profiling scripts. Is there a way to call the py.test test-discovery module so I can retrieve all tests of the project recursively? (the unittest discovery will not suffice since we yield a lot of parametrized tests in generator functions which are not recognized by unittest). This way I could at least solve the problem with only 1 additional script.
Here is a work-around. Create an additional python script with the following contents (adapt the path to the tests-root accordingly):
import os
import pytest
if __name__ == '__main__':
source_dir = os.path.dirname(os.path.abspath(__file__))
test_dir = os.path.abspath(os.path.join(source_dir, "../"))
pytest.main(test_dir, "setup.cfg")
The script filename must not start with test_, else pycharm will force you to run it with py.test. Then right-click the file and run it with Profile.
This also comes in handy for running it with Coverage.

Is it possible to run all unit test?

I have two module with two different classes and their corresponding test classes.
foo.py
------
class foo(object):
def fooMethod(self):
// smthg
bar.py
------
class bar(object):
def barMethod(self):
// smthg
fooTest.py
------
class fooTest(unittest.TestCase):
def fooMethodTest(self):
// smthg
barTest.py
------
class barTest(unittest.TestCase):
def barMethodTest(self):
// smthg
In any, test and source module, file, I erased the if __name__ == "__main__": because of increasing coherency and obeying object-oriented ideology.
Like in Java unit test, I'm looking for creating a module to run all unittest. For example,
runAllTest.py
-------------
class runAllTest(unittest.TestCase):
?????
if __name__ == "__main__":
?????
I looked for search engine but didn't find any tutorial or example. Is it possible to do so? Why? or How?
Note: I'm using eclipse and pydev distribution on windows machine.
When running unit tests based on the built-in python unittest module, at the root level of your project run
python -m unittest discover <module_name>
For the specific example above, it suffices to run
python -m unittest discover .
https://docs.python.org/2/library/unittest.html
You could create a TestSuite and run all your tests in it's if __name__ == '__main__' block:
import unittest
def create_suite():
test_suite = unittest.TestSuite()
test_suite.addTest(fooTest())
test_suite.addTest(barTest())
return test_suite
if __name__ == '__main__':
suite = create_suite()
runner=unittest.TextTestRunner()
runner.run(suite)
If you do not want to create the test cases manually look at this quesiton/answer, which basically creates the test cases dynamically, or use some of the features of the unittest module like test discovery feature and command line options ..
I think what you are looking for is the TestLoader. With this you can load specific tests or modules or load everything under a given directory. Also, this post has some useful examples using a TestSuite instance.
EDIT: The code I usually have in my test.py:
if not popts.tests:
suite = unittest.TestLoader().discover(os.path.dirname(__file__)+'/tests')
#print(suite._tests)
# Print outline
lg.info(' * Going for Interactive net tests = '+str(not tvars.NOINTERACTIVE))
# Run
unittest.TextTestRunner(verbosity=popts.verbosity).run(suite)
else:
lg.info(' * Running specific tests')
suite = unittest.TestSuite()
# Load standard tests
for t in popts.tests:
test = unittest.TestLoader().loadTestsFromName("tests."+t)
suite.addTest(test)
# Run
unittest.TextTestRunner(verbosity=popts.verbosity).run(suite)
Does two things:
If -t flag (tests) is not present, find and load all tests in directory
Else, load the requested tests one-by-one
I think you could just run the following command under the folder where your tests files are located:
python -m unittest
as mentioned here in the doc that "when executed without arguments Test Discovery is started"
With PyDev right click on a folder in Eclipse and choose "Run as-> Python unit-test". This will run all tests in that folder (the names of the test files and methods have to start with "test_".)
You are looking for nosetests.
You might need to rename your files; I'm not sure about the pattern nose uses to find the test files but, personally, I use *_test.py. It is possible to specify a custom pattern which your project uses for test filenames but I remember being unable to make it work so I ended up renaming my tests instead.
You also need to follow PEP 328 conventions to work with nose. I don't use IDEs with Python but your IDE may already follow it---just read the PEP and check.
With a PEP 328 directory/package structure, you can run individual tests as
nosetests path.to.class_test
Note that instead of the usual directory separators (/ or \), I used dots.
To run all tests, simply invoke nosetests at the root of your project.

how to know if my Python tests are running in coverage mode?

I am running Ned Batchelder's coverage module on continuous integration using Travis CI but I want to run only integration tests and skip functional ones because they take too long and coverage measurement is not affected by them.
I created a special configuration for this, but I want to know if there is an alternate method of knowing, inside a Python script, is the code is being run by coverage or not.
nose can definitely help with it:
Cover: code coverage plugin
Attribute selector plugin
you can mark tests with #attr("no-coverage") decorator and run your coverage tests with -a '!no-coverage' option
nose-exclude plugin
you can exclude specific test dirs and test files from running using --exclude-dir and --exclude-dir-file options
Hope that helps.
Based on the wording of your question I am assuming that you are not limiting what tests you are running with coverage and would like the functional tests to notice they are being run with coverage, and do nothing. A hacky way might be to look at sys.argv in the functional tests and do things differently if you detect coverage usage. But I think a better approach would be to have functional tests and unit tests in separate sibling directories, and tell coverage to run only the tests in the unit test directory. Potentially you could also use the --omit option to limit which tests are being run.
Travis CI provides a couple of environment variables that can be used for this; in my case any of this will serve:
CI=true
TRAVIS=true
even as both answers provided before were really useful, I think this solution is easier to implement for what I need.
I needed to determine if my tests were running under plain debug mode, with coverage, or just normally. After a good deal of experimentation I came up with this:
import sys
# Detect PyCharm debugging mode
get_trace = getattr(sys, 'gettrace', lambda: None)
if get_trace() is None:
debug = False
print('runnin normsies')
else:
debug = True
print('debuggin')
if 'coverage' in sys.modules.keys():
print('covered')
Not sure how robust it is, but it works for me.
Here's an implementation of the check whether a test is run in coverage mode. The nice thing about this is that you can use gettrace_result to check other conditions, e.g., whether the test is run by a debugger instead of coverage:
import sys
def is_run_with_coverage():
"""Check whether test is run with coverage."""
gettrace = getattr(sys, "gettrace", None)
if gettrace is None:
return False
else:
gettrace_result = gettrace()
try:
from coverage.pytracer import PyTracer
from coverage.tracer import CTracer
if isinstance(gettrace_result, (CTracer, PyTracer)):
return True
except ImportError:
pass
return False
You can use pytest.mark.skipif to skip tests that shouldn't be run in coverage mode.
#pytest.mark.skipif(is_run_with_coverage())
def test_to_skip_in_coverage_mode():
...
From the coverage.py documentation:
Coverage.py sets an environment variable, COVERAGE_RUN to indicate
that your code is running under coverage measurement.
Important: this option is only available in version 6.1 and later of the coverage module.
If detectcoverage.py contains:
import os
def detect_coverage():
return os.environ.get('COVERAGE_RUN', None) is not None
if detect_coverage():
print("running in coverage mode")
else:
print("not running in coverage mode")
then running that looks like:
$ coverage run detectcoverage.py
running in coverage mode
$ python detectcoverage.py
not running in coverage mode

Django test runner not finding tests

I am new to both Python and Django and I'm learning by creating a diet management site but I've been completely defeated by getting my unit tests to run. All the docs and blogs I've found say that as long as it's discoverable from tests.py, tests.py is in the same folder as models.py and your test class subclasses TestCase, it should all get picked up automatically. This isn't working for me, when I run manage.py test <myapp> it doesn't find any tests.
I started with all my tests in their own package but have simplified it down to all tests just being in my tests.py file. The current tests.py looks like:
import unittest
from pyDietTracker.models import Weight
from pyDietTracker.weight.DisplayDataAdapters import DisplayWeight
class TestDisplayWeight(unittest.TestCase):
def setUp(self):
pass
def tearDown(self):
pass
def testGetWeightInStone_KG_Correctly_Converted(self):
weight = Weight()
weight.weight = 99.8
testAdapter = DisplayWeight(weight)
self.assertEquals(testAdapter.GetWeightInStone(), '15 st 10 lb')
I have tried it by subclassing the Django TestCase class as well but this didn't work either. I'm using Django 1.1.1, Python 2.6 and I'm running Snow Leopard.
I'm sure I am missing something very basic and obvious but I just can't work out what. Any ideas?
Edit: Just a quick update after a comment
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.admin',
'pyDietTracker',
)
To get the tests to run I am running manage.py test pyDietTracker
I had the same issue but my root cause was different.
I was getting Ran 0 tests, as OP.
But it turns out the test methods inside your test class must start with keyword test to run.
Example:
from django.test import TestCase
class FooTest(TestCase):
def setUp(self):
pass
def tearDown(self):
pass
def this_wont_run(self):
print 'Fail'
def test_this_will(self):
print 'Win'
Also the files with your TestCases in them have to start with test.
If you're using a yourapp/tests package/style for unittests, make sure there's a __init__.py in your tests folder (since that's what makes it a Python module!).
I can run test for specific apps e.g.
python project/manage.py test app_name
but when I run
python project/manage.py test
0 tests was found
Figure out I need to run this in the same directory as manage.py
so the solution would be, cd to project directory and run
python manage.py test
In my case, the app folder itself was missing an __init__.py. This results in the behaviour that the test will be run with python manage.py test project.app_name but not with python manage.py test.
project/
app_name/
__init__.py # this was missing
In my case, I typed def instead of class. Instead of
class TestDisplayWeight(TestCase): # correct!
I had
def TestDisplayWeight(TestCase): # wrong!
This may also happen when you are using a tests module instead of a tests.py. In this case you need to import all the test classes into the __init__.py of your tests module, e.g.
tests/
__init__.py
somemodule.py
In your __init__.py you now need to import the somemodule like this:
from .somemodule import *
This also happens if you have a syntax error in your tests.py.
Worked it out.
It turns out I had done django-admin.py startproject pyDietTracker but not python manage.py startapp myApp. After going back and doing this, it did work as documented. It would appear I have a lot to learn about reading and the difference between a site and an app in Django.
Thank you for your help S.Lott and Emil Stenström. I wish I could accept both your answers because they are both helped alot.
Most important lesson Tests only work at the app level not the site level
Here's another one that I've just had: Check your test files are not executable. My virtualbox auto-mounted them as executable so the test discover missed them completely. I had to add them into the relevant __init__.py files before someone told me what the issue was as a work around, but now they are removed, and non-executable and everything _just_works.
in my case, I miss starting my functions name with test_
and when run my test with :
python manage.py test myapp
result was :
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK
Destroying test database for alias 'default'...
it seems Django cannot recognize my tests!
then i change myproject/myapp/test.py file like this :
from django.test import TestCase
# Create your tests here.
class apitest(TestCase):
def test_email(self):
pass
def test_secend(self):
pass
after that result is:
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
..
----------------------------------------------------------------------
Ran 2 tests in 2.048s
OK
Destroying test database for alias 'default'...
I know I am late at this point but I also had trouble with
Found 0 test(s).
System check identified no issues (1 silenced).
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK
I have followed all the steps still I was facing the same issue. My fix was I missed __init__.py file in the test directory. Adding the file and re-running the command solved my issue.
HIGHLIGHTING IT A BIT:
Make sure you have __init__.py file
I had this happen when I had a test.py file, and a test/ subdirectory, in the same Django app directory. I guess I'm confusing python or the test runner whether I'm looking for a test module (in test.py) or a test package (in test/ subdir).
If you are trying to run a test in your main app, such as my_app/my_app/ make sure you have the following checked:
App name is listed in INSTALLED_APPS inside settings.py
Make sure your DATABASES['default'] inside settings.py is set properly
The App has a models.py (even if you are not using one, at least an empty one is required to be there)
Using this syntax
python manage.py test
instead of ./manage.py test solved this problem for me.
See https://docs.djangoproject.com/en/1.11/topics/testing/overview/
The most common reason for tests not running is that your settings aren't right, and your module is not in INSTALLED_APPS.
We use django.test.TestCase instead of unittest.TestCase. It has the Client bundled in.
https://docs.djangoproject.com/en/1.11/topics/testing/tools/#django.test.TestCase
I had the same problem, turns out I saved the __init__ as a python file but it did not put .py at the end of its name. I added .py at the end of file's name. it was ok afterwards
(in other words, I had created __init__ instead of __init__.py )
In the same file, I had two test classes with the SAME NAME, and of course this prevented all tests from running.
I created a method called run in my test class which turned out to be a very bad idea. Python could see that I wanted to run tests, but was unable to. This problem is slightly different, but the result is the same - it made it seem as if the tests couldn't be found.
Note that the following message was displayed:
You want to run the existing test: <unittest.runner.TextTestResult run=0 errors=0 failures=0>
Run --help and look for verbose. Crank it to max.
I ran manage.py test --verbose and found this debug output right at the top:
>nosetests --with-spec --spec-color --verbose --verbosity=2.
Oh look! I had installed and forgotten about nosetests. And it says --verbosity=2. I figured out that 3 is the max and running it with 3 I found lots of these:
nose.selector: INFO: /media/sf_C_DRIVE/Users/me/git/django/app/tests/test_processors.py is executable; skipped
That gave me the right hint. It indeed has problems with files having the x-bit set. However, I was thrown off the track as it had run SOME of the tests - even though it explicitly said it would skip them. Changing bits is not possible, as I run the tests in a VM, sharing my Windows NTFS-disk. So adding --exe fixed it.
Had the same issue and it was because my filename had a - char in its name.
My filename was route-tests.py and changed it to route_tests.py
If you encounter this error after upgrading to Django 3, it might be because the -k parameter changed meaning from:
-k, --keepdb Preserves the test DB between runs.
to
-k TEST_NAME_PATTERNS Only run test methods and classes that match the pattern or substring. Can be used multiple times. Same as unittest -k option.
So just replace -k with --keepdb to make it work again.
Django engine searches files and folders with test_ prefix (inside of a tests folder). In my case it was simple solution.
So, be sure to checkout file/folder name starts with it.
I had the same problem, it was caused by init.py at the project root - deleted that, all tests ran fine again.
This is late. but you can simply add your app name in front of importing models. like
from myapp.models import something
This works for Me.
In Django, methods in test classes must start with "test" keyword. for example test_is_true(). methods name like is_true() will not execute.

Categories