-
Notifications
You must be signed in to change notification settings - Fork 112
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
More powerful whitelisting system #47
Comments
This seems like mostly the same as what we discussed in #28 but for different reasons obviously. Maybe one should be able to just plug in an arbitrary python function that gets called to ask for exclusion? |
Actually, thinking more about this it would be interesting if you could explain more about your situation. In my experience mutating constants is one of the more useful things for finding lacking tests or even outright bugs. I don't understand your description. |
If you have |
Ah, I see. Well yea, in that case the current system to deal with it is |
Just to chime in for a similar issue. I was experiencing false positives due to mutmut modifying the
It would likely be good practice to avoid mutating misc python doc/notes variables e.g. __author__ = "Software Authors Name"
__copyright__ = "Copyright (C) 2004 Author Name"
__license__ = "Public Domain"
__version__ = "1.0" |
Yea, maybe a global and built in whitelist would be a good idea. I have another candidate for that: __import__('pkg_resources').declare_namespace(__name__) we always have to put a pragma no mutate on those. |
@nklapste I've released a new version of mutmut that ignored a bunch of these by default. It's also got an overhauled cache system that is way better. Give it a try! |
A related issue that I'm dealing with: I want to skip mutations on log messages. ex:
|
A more flexible approach, that could live outside the actual source would be nice. E.g. having a callback in the config like mentioned already. |
For the case @lundybernard has, the line obviously won't do because the mutated string is on a different line than If we allow python code in the config file, then we should probably require (and validate!) that the callback provided has |
I can't help but feel that needing to achieve 100% killed mutants will always be an endless game of whack-a-mole that isn't worth playing. I would prefer a different strategy that accepts the fact that false positives will occur. Take a look at how the PHP mutation testing framework 'Infection' handles this: https://infection.github.io/guide/using-with-ci.html The notion of not being able to achieve 100% killed mutants is baked into the design of the tool. I think this is a much better approach than requiring that everything be whitelisted. |
Hitting any percentage above zero is also an endless game of whack a mole to be fair :) It's just harder to reach 100% the first time, that's the big difference. I do agree your underlying point though: ratchet are a powerful tool to be able to slowly make things better instead of always be perfect or giving up. So yea, this is a feature worth having. But I do get the feeling that we'd like something smarter! Just having a fixed percentage for the entire project doesn't seem like a very good ratchet to me. |
In my case I would like to tell mutmut that None makes no difference in that context, but do not want to stop it from other mutations. (Yes, first I looked into possibilities to run the tests with a dynamic typechecker, but did not find any useable solution. Plus neither mypy nor pytype finds anything wrong with the mutated line...). I would also like to comment on some use cases above:
|
#138 is the same thing as this issue really. |
Another use-case: I maintain a parser library, where parse errors are manifested as "raise ParseException" all over the code base. I don't care enough about the exact phrasing of the error messages to test for that string in all my tests, so mutmut (correctly) finds all instances of ParseException and shows them as errors. I would like a way to filter away all those errors (which are about 50% of all errors in my case), so I could focus on the important stuff it find. Maybe I could run this in CI with a good way to filter out things I don't need tested? "# pragma: no mutation" would work in my case, but feels ugly and verbose, and is easy to miss for contributors that want to add code. Some ideas of how this could be handled:
|
I had an idea.. what if the answer is "all of the above"? Matching a full line with "contains" is option number 1, then regexes as option number 2, then specifying a python function that gets passed the line and the AST node as number 4. But starting with 1 and maybe 2 of course. The reason I'm thinking "all of the above" is because there is a huge usability and speed difference between those options. Just finding if a string contains another string is super fast and easy to understand so we prefer that if possible. Any thoughts? |
To be clear: My use-case would be solved with just step 1. |
I guess most use cases would be yes. |
@joshz123 wrote:
|
It's not been very clear to me what we need. #pragma no mutate on a block? Or #pragma no mutate start/end? What would cover your use case? Or could regexes handle it? |
#pragma no mutate start/end would cover my use case. Sorry for any confusion |
I would vote to an annotation instead of a pragma. Of coure it is just a matter of taste. My use case would be covered by the ability to mark individual lines. |
@magwas thst doesn't make sense. Annotations only exist for functions and classes, that's way too limited. And single lines already exist. |
Well, ok, python is not java. Sorry. |
I have an experimental hook API on master now that I have used to mutation test iommi. You can check out how I use it here: https://github.com/TriOptima/iommi/blob/master/mutmut_config.py I use it to narrow the test suite based on the file being mutated. This is dramatic speedup (although more mutants probably survive, which I actually think is good). It's the implementation of my thinking on testing and modules (https://kodare.net/2019/10/18/which_unit.html) This system also has a way to skip mutations. Set |
This is now released. |
I've now added a bit of documentation in the readme on this. |
Similar to #138 I'd like to see if a feature could be added to allow skipping mutations when a function is an instance of a specified object. Primarily my use case is: avoid mutating strings to be logged (instance of |
This is absolutely the correct issue! I can't really use the type of the object, as mutmut is just working with the source code, not the running process. But it's pretty simple to add a rule that matches the line against Would you like some help setting this up for your use case? |
Please! Here are a few examples of the entries I'd like to avoid mutating:
I don't think having test cases for these is really the point of testing. Thanks! |
in def pre_mutation(context):
if context.current_source_line.strip().startswith('log.'):
context.skip = True that's the basic one, I hope you see how it's trivial to add mylog, input and whatever else you need. |
Indeed, that will be easy to build upon. |
Let me know how it goes! |
I have the desired exclusions working as I intended, though some I would have thought have been defaults. :) Here's a sample:
|
Well, it depends on the program too much to be a default I think. |
Very true. However, more examples in https://github.com/boxed/mutmut#advanced-whitelisting-and-configuration would be helpful for those who are just finding this project. Looking at the code doesn't immediately provide satisfaction, especially burined 400+ lines into a 1200+ line file. That's not a complaint. I'm pointing out that the code I posted above still doesn't immediately flow from examining the source:
|
I added an example for the case about just matching the line. Seems like it should cover many use cases. |
can you show how to do it in the "AST node way" for multiline (log) calls? e.g..: app.logger.error(
err,
extra = get_extra_info(
code = 500,
error = ErrorInfo(
msg=str(err), code=500, stack_trace=traceback.format_exc(), dbg_msg="type 1 error"
).dict()
)
) |
hmm.. Reading through the code, it seems doing it on the AST level with the current API isn't really a thing. You'd have to parse the file again with parso and then look at the AST.... |
For my use, all of the suggestions are useful, but I cannot really persist a bunch of |
A lot of surviving mutants in a project are due to changing constants, e.g.
FOO = 1
, whereFOO
itself is used in tests then also.Killing those would need a test where the value itself is used, which does not make much sense, does it?
I think it would be good if those mutations could be skipped (e.g. by not mutating anything that matches
[A-Z_]+
maybe?It would be good if those could be deselected either by name of the mutation (which would need to be something like
mutate-constant-X
), or by specifying a pattern of identifiers not to mutate.(it is not possible to deselect mutations currently, is it?)
The text was updated successfully, but these errors were encountered: