Pytest fails when using pyhamcrest raises - python-3.x

Currently I have a test cases like the following:
def test_foo(self):
assert_that(self.target.do(), raises(FileNotFoundError))
Which passes using the standard python unittest framework, however if I change to use pytest, it fails. Switching to the pytest syntax works (as below), but why doesn't the pyhamcrest matcher work in this case?
def test_foo(self):
with pytest.raises(FileNotFoundError):
self.target.do()

PyHamcrest's raises() matcher requires you to make the call with the calling() function - see the tutorial. So, in your case you'd want:
assert_that(calling(self.target.do), raises(FileNotFoundError))

Related

Why is doctest skipping tests on imported methods?

I have a python module some_module with an __init__.py file that imports methods, like this:
from .some_python_file import some_method
some_method has a docstring that includes doctests:
def some_method():
"""
>>> assert False
"""
But when I run doctest on the module, it passes even if the tests should fail.
import some_module
# How do I get this to consistently fail, regardless of whether
# `some_module.some_method` was declared inline or imported?
assert doctest.testmod(some_module).failed == 0
If I instead define some_method within the __init__.py file, the doctest correctly fails.
Why are these two situations behaving differently? The method is present and has the same __doc__ attribute in both cases.
How do I get doctest to run the tests defined in the dostrings of methods that were imported into the module?
In Python a module is define by a single file and in your case some_python_file is a module while __init__ is another one. Doctest has a check to run tests only for examples reachable from the module which can be found here.
The best way to see this behaviour in practice is to use PDB and pdb.set_trace() right before you call doctest.testmod(some_module) and step inside to follow the logic.
LE:
Doctest ignores imported methods per this comment. If you want to be able to run your test you should probably define a main function in your module and run the test test with python some_module.py. You can follow this example.
To achieve your expected behaviour you need to manually create a __test__ dict in your init file:
from .some_python_file import some_method
__test__ = {"some_method": some_method}
See this link as well.
Objects imported into the module are not searched.
See docs on which docstrings are examined.
You can can inject the imported function into the module's __test__ attribute to have imported objects tested:
__test__ = {'some_method': some_method}
I stumbled upon this question because I was hacking a __doc__ attribute of an imported object.
from foo import bar
bar.__doc__ = """
>>> assert True
"""
and I was also wondering why the doctest of bar did not get executed by the doctest runner.
The previously given answer to add a `__test__` mapping solved it for good.
```python
__test__ = dict(bar=bar.__doc__)
I think the explanation for this behaviour is the following. If you are using a library, lets say NumPy, you do not want all of their doctests to be collected and run in your own code.
Simply, because it would be redundant.
You should trust the developers of the library to (continuously) test their code, so you do not have to do it.
If you have tests defined in your own code, you should have a test collector (e.g. pytest) descend into all files of your project structure and run these.
You would end up testing all doctests in used libraries, which takes a lot of time. So the decision to ignore imported doctests is very sane.

Modify and run nose Doctest Plugin

I have been using nose.run(argv=['--with-doctest'], addplugins=[...]) successfully but now I am needing to subclass nose.plugins.doctests.Doctest so that I can modify its loadTestsFromModule method. I have other plugins (by subclassing nose.plugins.Plugin) which are working, but I have not been successful run the doctests.
from nose.plugins.doctests import Doctest
class TestDocs(Doctest):
def loadTestsFromModule(self, module):
# add something here
super(testDocs, self).__init__(module)
I have tried the following:
nose.run(addplugins=[TestDocs()])
nose.run(plugins=[TestDocs()])
nose.run(argv=['--with-testdocs'])
nose.run(argv=['--with-testdocs'], addplugins=[TestDocs()])
I also tried another name, in case it including 'test' was an issue. And I tried using DocTest directly, but have been unable to activate doctests without using --with-doctest.
nose.run(addplugins=[Doctest()])
nose.run(plugins=[Doctest()])
How can I activate doctests using the plugin?
This combination allowed for the custom subclass of Doctest using nose.run.
nose.run(argv=['--with-testdocs'], plugins=[TestDocs()])
It was helpful to use argv=['--plugins'] as it highlighted the difference between plugins= and addplugins= since I was already using addplugins for other Plugins.:
>>> nose.run(argv=['--plugins'], plugins=[TestDocs()],
addplugins=[OtherPlugin(), AnotherPlugin()])
Plugin OtherPlugin
Plugin testdocs
Plugin AnotherPlugin

How to use Spock from the Command Line

I am writing a set of groovy scripts to be used as part of a Jenkins Pipeline Library. Currently I am using plain old JUnit to test them but would like to switch to Spock. I simply run the tests from the command line by invoking the following groovy script.
import groovy.util.AllTestSuite
import junit.textui.TestRunner
System.setProperty(AllTestSuite.SYSPROP_TEST_DIR, "./tests")
System.setProperty(AllTestSuite.SYSPROP_TEST_PATTERN, "**/*Test.groovy")
TestRunner.run(AllTestSuite.suite())
I am trying to figure what the equivalent script would be to run Spock specifications. My first attempt was to switch the SYSPROP_TEST_PATTERN to "**/*Spec.groovy. I have one ...Spec.groovy file written and sitting under ./tests that looks like this:
#Grab(group='org.spockframework', module='spock-core', version='1.0-groovy-2.3')
import spock.lang.*
class UtilsSpec extends Specification {
def "Just testing"() {
expect:
1 + 1 == 2
}
}
When I invoke my groovy script though I get:
java.lang.RuntimeException: Don't know how to treat
/SourcCode/jenkins/pipeline-utils/tests/JustTestingSpec.groovy as a
JUnit test
That makes sense. I need to be using Sputnik but I've looked at the Spock and Sputnik source, and the Spock example project but these all assume you are using maven or gradle. I can't figured out the right way to invoke Sputnik directly. Any ideas?
Even though what you ask is possible and BalRog has already suggested a solution, in the long run it is better if you just use Gradle or Maven to run your tests from command line.
All Jenkins tutorials you will encounter will talk about Maven and/or Gradle and thus it would make much more sense to use a build system than custom scripts.

jython2.2.1 AttributeError: 'javainstance' object has no attribute '__call__'

I'm having trouble trying to run jython code embedded in a compiled groovy application. The same jython code works fine when it is embedded in a java application (The Grinder 3.1)
In the groovy code I use the org.python.util.PythonInterpreter class (from jython 2.2.1) to create a callable instance of a class called TestRunner (this is a requirement from The Grinder).
Illustrative jython code example:
class TestRunner:
def __init__(self):
doinitstuff()
def __call__():
a = A()
a.work()
class A:
def __init__(self):
self.b = B()
def work(self):
print "Calling methodcall"
self.b.methodcall()
class B:
def __init__(self):
self.webservice = WebServiceStubImplementedInJava()
print str(self.webservice)
def methodcall(self):
print "In methodcall"
try:
return self.webservice.soapmethod()
except:
log_error()
raise
Here is the output when I run the above code:
The TestRunners __call__() method will invoke the work() method of a class A instance, and the webservice stub's toString output is printed.
The "Calling methodcall" message is printed.
The "In methodcall" message is never printed, and instead I get: AttributeError: 'javainstance' object has no attribute '__call__'. The stacktrace ends with self.b.methodcall()
Do you have any idea why the invocation of self.b.methodcall() should result in AttributeError: 'javainstance' object has no attribute __call__
Adding some context to the problem...
I'm trying to use a Groovy class to execute the work that a Grinder worker thread would perform when we performance test our product.
I use groovy just for the sake of "less verbose code", but might have to switch over to plain old java if it's groovy that causes the problem.
The reason for doing this is that I need to find out which files are actually used by Grinder for a given test scenario.
We have hundreds of *.py files and configuration files etc, but only a subset of them are used for one specific test scenario. All of them are used in some test scenario.
This makes it quite hard for a "beginner" to understand how to configure a test so I'm trying to build a "test configurator wizard" that set up a test scenario without forcing the user/tester to edit all config files manually.
This wizard will collect the relevant files from a "repository" and put them in a folder where the "Grinder Console" can present them to the user.
So, the way I use to find out which files are used by Grinder is to use AOP (AspectJ) to capture all calls to java.io.FileInputStream(java.io.File) from any code in the org.python.util and org.python.core packages.
The "advice" I apply to these join-points is to print the file name to System.out.
I use load-time weaving for this, so I can run the groovy/java/jython code with our without
AOP enabled. The AttributeErrorproblem occurs regardless if I have AOP enabled or not.
I have a vague suspicion that the AttributeError problem could be caused by some classloader mismatch when a "groovy" class executes the PythonInterpreter methods, but I'm far from sure about this.
I'm not sure if groovy is doing any kind of runtime bytecode editing when it loads classes and if that confuses the PythonInterpreter.
The groovy code itself is precompiled so I use the regular java.exe to launch the process.

I'm getting an invalid syntax error in configparser.py

I'm trying to get the pymysql module working with python3 on a Macintosh. Note that I am a beginning python user who decided to switch from ruby and am trying to build a simple (sigh) database project to drive my learning python.
In a simple (I thought) test program, I am getting a syntax error in confiparser.py (which is used by the pymysql module)
def __init__(self, defaults=None, dict_type=_default_dict,
allow_no_value=False, *, delimiters=('=', ':'),
comment_prefixes=('#', ';'), inline_comment_prefixes=None,
strict=True, empty_lines_in_values=True,
default_section=DEFAULTSECT,
interpolation=_UNSET):
According to Komodo, the error is on the second line. I assume it is related to the asterix but regardless, I don't know why there would be a problem like this with a standard Python module.
Anyone seen this before?
You're most certainly running the code with a 2.x interpreter. I wonder why it even tries to import 3.x libraries, perhaps the answer lies in your installation process - but that's a different question. Anyway, this (before any other imports)
import sys
print(sys.version)
should show which Python version is actually run, as Komodo Edit may be choosing the wrong executable for whatever reason. Alternatively, leave out the parens and it simply fails if run with Python 3.
In Python 3.2 the configparser module does indeed look that way. Importing it works fine from Python 3.2, but not from Python 2.
Am I right in guessing you get the error when you try to run your module with Komodo? Then you just have configured the wrong Python executable.

Resources