-
Notifications
You must be signed in to change notification settings - Fork 55
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
raise value error from the constructor level #290
Conversation
Pull Request Test Coverage Report for Build 661743676Warning: This coverage report may be inaccurate.This pull request's base commit is no longer the HEAD commit of its target branch. This means it includes changes from outside the original pull request, including, potentially, unrelated coverage changes.
Details
💛 - Coveralls |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@EricLiclair thanks a lot for contributing and for the update.
Could you please add test cases to cover your changes?
It ensures that this PR actually addresses #233 and that no future regressions might happen (at least not un-intentional regression)?
testslide/matchers.py
Outdated
@@ -53,6 +53,8 @@ class _AndMatcher(_AlreadyChainedMatcher): | |||
""" | |||
|
|||
def __init__(self, a: Matcher, b: Matcher) -> None: | |||
if not isinstance(a, Matcher) or not isinstance(b, Matcher): | |||
raise ValueError("Not of type Matcher") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit. I would have more explicit wording in here eventually pointing to what is not a Matcher
. Like adding the presentation of a
or b
.
This would help developers receiving such error to be guided toward what to fix instead of having them discover it themselves
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes am working on it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@EricLiclair , sorry for being pedantic ... I hope that you would appreciate it.
I do have some reserves on what the tests are actually trying to test.
My understanding is that the tests (that might benefit from a small re-org, as for the comments) are testing the exact if
statements that have been added, but is totally unclear to me how a user would eventually get into that flow. Having this understanding would be beneficial to ensure that wording is consistent and helpful for the framework user.
About
The
make install_build_deps
does not installtypeguard
andpsutil
.
This is expected because typeguard
and psutil
are dependencies of the library and not needed to start the build/test/lint of the library. You should be using make install_deps
to install the library dependencies (as it was suggested in here)
@@ -279,6 +279,34 @@ def testCannotChainMoreThanTwo(self): | |||
with self.assertRaises(testslide.matchers.AlreadyChainedException): | |||
testslide.matchers.Any() ^ testslide.matchers.AnyStr() ^ testslide.matchers.AnyInt() | |||
|
|||
def testValueError(self): | |||
# tests for _AndMatcher constructor call | |||
self.assertRaises(ValueError, testslide.matchers._AndMatcher, 10, 30) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a few notes around the tests:
- I would highly recommend to use the
assetRaises
as context manager such that the code to test is written in a more "natural" form and please assert that the content of the exception matches your expectations (example below). NOTE This applies to all the assertions - please create multiple tests with a very scoped objective. In case
testValueError
would be failing we would have 9 assertions (as for now) to verify and this makes it very hard to scale - Even though the unittest might be valid I struggle to match the case to how a user would eventually be able to trigger such error.
A user of the testing framework should not be using "private" (underscore-prefixed methods/classes) components of the framework. Please create some tests triggering the case that you are covering by this PR.
Example
with self.assertRaisesRegex(ValueError, ${regex matching the string representation of the exception}):
testslide.matchers._AndMatcher(10, 30)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi, thanks for your valuable response and yes I do appreciate it. I tried to figure out a way to address the original issue. I believe I understood what needs to be done, but I am kind of stuck as to which all matchers need to be updated. Previously I was changing the private methods _AndMatcher
, _OrMatcher
and _XorMatcher
. But after your last response I kind of believe that those are not where update needs to be done.
Also I tried figuring out what all cases might trigger the error I was trying to raise.
I'm stuck.
I need your help, if you could guide me, where and what all to be updated.
What I have from the past responses:
- Use
isinstance()
. - Error to be raised
ValueError
with an intuitiveerro message
. - Once updated, add tests for the updated code.
- Multiple tests with very scoped objectives.
- Natural representation of the test case using
assertRaise
as context manager.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll have a small step back and check what the issue reports.
It does mention that if we would be using AnyInstanceOf(not_a_type)
it would throw a TypeError
because not_a_type
is not a type.
>>> isinstance(1, 2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: isinstance() arg 2 must be a type or tuple of types
While it would be better to have a more explicit exception matching that the AnyInstanceOf
matcher was not properly configured.
Now, the comments provided so far were a mixture between python-ism and having tests that help us to ensure that what is fixed today does not get broken/removed tomorrow without a direct intent.
What would I expect to see?
Essentially, AnyInstanceOf
is used when you want to match parameters into mocked methods.
An example of a "correct" usage would be
class C:
def foo(self, obj: Any) -> str:
if isinstance(obj, (str, int)):
return "string or integer"
else:
return str(obj)
class TC(TestCase):
def test_C_foo(self) -> None:
c = C()
self.mock_callable(c, "foo").for_call(AnyInstanceOf(int)).to_return_value("Mocked it properly")
self.assertEqual(c.foo(1), "Mocked it properly")
self.assertEqual(c.foo(2), "Mocked it properly")
with self.assertRaises(UnexpectedCallArguments):
# This raises because c.foo has no defined behaviour if it gets called with non `int` param
c.foo("a string")
but now what would happen if I would have a test like
def test_triggering(self) -> None:
c = C()
self.mock_callable(c, "foo").for_call(AnyInstanceOf(2)).to_return_value("Canned response")
c.foo()
It would fail with a very odd exception like
1) t.TC: test_triggering
1) TypeError: isinstance() arg 2 must be a type or tuple of types
File "t.py", line 26, in test_triggering
c.foo(42)
which makes little sense. Would not it be better to have had something like (fully made up exception here)
1) t.TC: test_triggering
1) ValueError: AnyInstanceOf(...) expects a type while an `int` (`2`) was provided
File "t.py", line 26, in test_triggering
self.mock_callable(c, "foo").for_call(AnyInstanceOf(2)).to_return_value("Canned response")
When I mentioned
A user of the testing framework should not be using "private" (underscore-prefixed methods/classes) components of the framework. Please create some tests triggering the case that you are covering by this PR.
I meant to create a test like test_triggering
that shows how the user would "mis-use" the matchers and that they would now receive the ValuleError
exception.
What:
#233
Why:
An error was raised when the comparison of two non-similar type data were compared. To be more technically correct, the error should be raised at the time of creating an instance. And thereby this solution.
How:
Compared the input arguments, passed at the time of constructor call, with the type of class Matcher. If the two type do not match, a Value Error is raised.
Risks:
No Such risks are possible as far as I understand the use of the particular constructors. The only issues am concerned about is that the
make install_build_deps
does not installtypeguard
andpsutil
. That can be a reason for the tests to fail.Checklist:
Ensured the test suite passes
Made sure your code lints
Completed the Contributor License Agreement ("CLA")
Added tests, if you've added code that should be tested
Updated the documentation, if you've changed APIs N/A
Two points to draw attention.
make install_build_deps
does not installtypeguard
andpsutil
.