Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mutation not killed when it should be with a method with an auto-injected field

I have the following:

public class UnsetProperty extends Command {

    @Resource
    private SetProperty setProperty;

    public String parse(String[] args) {
        if (args.length != 4) {
            throw new RuntimeException("Incorrect number of arguments. Expected 4. Got " + args.length);
        }
        String publisher = args[0];
        String version = args[1];
        String mode = args[2];
        String property = args[3];

        /*
         * Unsetting a property is done by changing the current property to null.
         * Technically, the old property doesn't get changed, a new one is inserted with
         * a higher revision number, and it becomes the canonical one.
        */
        setProperty.setProperty(publisher, version, mode, property, null, false);
        return "";
    }
}

and the following test:

public class UnsetPropertyTest extends CommandTest {
    @Configuration
    public static class Config {

        @Bean(name = "mockSetProperty")
        public SetProperty getSetProperty() {
            return mock(SetProperty.class);
        }

        @Bean
        public UnsetProperty getUnsetProperty() {
            return new UnsetProperty();
        }

    }

    @Resource
    @InjectMocks
    private UnsetProperty unsetProperty;

    @Resource(name = "mockSetProperty")
    private SetProperty setProperty;

    // ... SNIP ...

    @Test
    public void testCallsSetPropertyWithCorrectParameters() throws SQLException, TaboolaException {
        final String[] args = new String[]{"publisher", "version", "mode", "property"};
        final String output = unsetProperty.parse(args);
        verify(setProperty).setProperty("publisher", "version", "mode", "property", null, false);
        // The above line should have killed the mutation!
        verifyNoMoreInteractions(setProperty);
        assertThat(output).isEqualTo("");
    }
}

The test passes, as expected. When I run it through PIT I get the following result

33   1. removed call to my/package/SetProperty::setProperty → SURVIVED

Line #33 is highlighted in the class code.

The tests examined are as follows:

  • my.package.UnsetPropertyTest.testCallsSetPropertyWithCorrectParameters(my.package.UnsetPropertyTest) (32 ms)
  • my.package.UnsetPropertyTest.testUnsetThrowsForIncorrectNumberOfParameters(my.package.UnsetPropertyTest) (3 ms)

Now:

  • When I change the test invoke parameters (args) the test fails. As expected
  • When I change the assertion (verify(setProperty).setProperty(...)) arguments the test fails. As expected.
  • When I manually comment out the function call highlighted in the first code block, the test fails.

Why does the mutation survive?

I'm using Java 8, Mockito 1.9.5 and PIT 1.1.4.

like image 907
Madara's Ghost Avatar asked Mar 16 '15 12:03

Madara's Ghost


People also ask

How can mutation be killed when performing mutation testing?

A mutation is killed if at least one test case fails when the test is repeated. If this does not happen, the test cases do not detect that the source code has been changed, or in other words: the test cases also consider a test object other than the original one as correct.

What is mutation test coverage?

Mutation Coverage Mutation testing is a testing technique used to improve the adequacy of tests and identify defects in code. The idea is to change the production code dynamically and cause the tests to fail.

What are the advantages of mutation testing?

Advantages of Mutation Testing Mutation testing helps find weak programs in the code that are responsible for bugs. It is also helpful in finding weak test cases (test cases that are not able to kill mutants). It helps the development team to check the quality of the source code.

Does mutation testing improve testing practices?

Our analyses suggest that developers using mutation testing write more tests, and actively improve their test suites with high quality tests such that fewer mutants remain.


1 Answers

Years later but no one seemed to mention that (Spring) @Resource and (Mockito) @InjectMocks are mutually exclusive solutions. You have multiple generated subclasses of UnsetProperty in play so PIT is simply confused about what's going on.

like image 127
drekbour Avatar answered Sep 25 '22 17:09

drekbour