Wrong mocked instance returned #404

Closed
Milbor opened this Issue Mar 31, 2017 · 4 comments

Comments

2 participants
@Milbor

Milbor commented Mar 31, 2017

Fails since 1.29
testng 6.9.10
Yet another unsuccessful upgrade from 1.25 to 1.31

@ContextConfiguration(classes = TestConfig.class)
public class SpikeTest extends AbstractTestNGSpringContextTests {
    @Capturing
    private SubManager manager;
    @Autowired
    private System system;
    private Entity stub = new Entity();

    @Test
    public void test() {
        new Expectations() {{
            manager.find();
            result = stub;
        }};
        final Entity actual = system.call();
        assertSame(actual, stub);
    }

    public static class System {
        @Autowired
        private SubManager manager;

        public Entity call() {
            return manager.find();
        }
    }

    public interface SubManager extends Manager {
    }

    public interface Manager {
        Entity find();
    }

    public static class Entity {
    }

    @Configuration
    public static class TestConfig {
        @Bean
        protected System system() {
            return new System();
        }

        @Bean
        protected SubManager manager() {
            return new SubManager() {
                @Override
                public Entity find() {
                    throw new UnsupportedOperationException();
                }
            };
        }
    }
}

@rliesenfeld rliesenfeld added the bug label Apr 1, 2017

@rliesenfeld rliesenfeld self-assigned this Apr 1, 2017

@rliesenfeld

This comment has been minimized.

Show comment
Hide comment
@rliesenfeld

rliesenfeld Apr 1, 2017

Member

As a workaround until the bug is fixed in release 1.32, the test could be written as follows (which is also shorter & simpler):

public final class SpikeUsingTestedTest {
   @Tested System system;
   @Injectable SubManager manager;
   final Entity stub = new Entity();

   @Test
   public void test() {
      new Expectations() {{ manager.find(); result = stub; }};

      Entity actual = system.call();

      assertSame(actual, stub);
   }

   public static class System {
      @Autowired private SubManager manager; // recommend using @Inject (javax.inject) instead
      public Entity call() { return manager.find(); }
   }

   public interface Manager { Entity find(); }
   public interface SubManager extends Manager {}
   public static class Entity {}
}
Member

rliesenfeld commented Apr 1, 2017

As a workaround until the bug is fixed in release 1.32, the test could be written as follows (which is also shorter & simpler):

public final class SpikeUsingTestedTest {
   @Tested System system;
   @Injectable SubManager manager;
   final Entity stub = new Entity();

   @Test
   public void test() {
      new Expectations() {{ manager.find(); result = stub; }};

      Entity actual = system.call();

      assertSame(actual, stub);
   }

   public static class System {
      @Autowired private SubManager manager; // recommend using @Inject (javax.inject) instead
      public Entity call() { return manager.find(); }
   }

   public interface Manager { Entity find(); }
   public interface SubManager extends Manager {}
   public static class Entity {}
}
@Milbor

This comment has been minimized.

Show comment
Hide comment
@Milbor

Milbor Apr 1, 2017

Well, yes for this simple test just presented to capture the bug.
However in our test cases we really need the "System" under test to be instantiated by Spring with all of it's bean dependencies and only mock out "SubManager".
I suppose @Capturing and @Autowired (or @Inject) is used correctly for this job as @tested would instantiate "System" by jMockit with only "SubManager" injected and would skip any other Spring beans.

Milbor commented Apr 1, 2017

Well, yes for this simple test just presented to capture the bug.
However in our test cases we really need the "System" under test to be instantiated by Spring with all of it's bean dependencies and only mock out "SubManager".
I suppose @Capturing and @Autowired (or @Inject) is used correctly for this job as @tested would instantiate "System" by jMockit with only "SubManager" injected and would skip any other Spring beans.

@rliesenfeld

This comment has been minimized.

Show comment
Hide comment
@rliesenfeld

rliesenfeld Apr 3, 2017

Member

The fix for previously reported issue #373 only works when using Verifications. The following test still fails:

@Test
public void recordMethodFromBaseInterfaceWhileCapturingASubInterface(@Capturing final SubItf sub)
{
    new Expectations() {{ sub.base(); }};

    SubItf impl = new SubItf() { @Override public void base() {} };
    impl.base();
}
Member

rliesenfeld commented Apr 3, 2017

The fix for previously reported issue #373 only works when using Verifications. The following test still fails:

@Test
public void recordMethodFromBaseInterfaceWhileCapturingASubInterface(@Capturing final SubItf sub)
{
    new Expectations() {{ sub.base(); }};

    SubItf impl = new SubItf() { @Override public void base() {} };
    impl.base();
}
@rliesenfeld

This comment has been minimized.

Show comment
Hide comment
@rliesenfeld

rliesenfeld Apr 3, 2017

Member

The @Capturing bug will (finally) be fixed soon, but just for the record, the @Tested annotation also supports recursive instantiation of "sub-beans" (see the fullyInitialized attribute). I actually use this in a real-world Spring 2.5 app instead of the Spring Test Context, since it's faster, cleaner (none of that noise that Spring spews to console output, less code in the test class), and Spring-agnostic (Java EE 6+ is supported as well, allowing for clean, fast integration tests which look the same with either Java EE or Spring).

Member

rliesenfeld commented Apr 3, 2017

The @Capturing bug will (finally) be fixed soon, but just for the record, the @Tested annotation also supports recursive instantiation of "sub-beans" (see the fullyInitialized attribute). I actually use this in a real-world Spring 2.5 app instead of the Spring Test Context, since it's faster, cleaner (none of that noise that Spring spews to console output, less code in the test class), and Spring-agnostic (Java EE 6+ is supported as well, allowing for clean, fast integration tests which look the same with either Java EE or Spring).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment