Skip to content
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

Support constructor injection when using Spring with @Qualifier #290

Closed
tuegeb opened this issue Jun 11, 2016 · 5 comments
Closed

Support constructor injection when using Spring with @Qualifier #290

tuegeb opened this issue Jun 11, 2016 · 5 comments
Assignees
Labels

Comments

@tuegeb
Copy link

@tuegeb tuegeb commented Jun 11, 2016

  • Version of JMockit that was used: 1.24
  • Description of the problem or enhancement request:
    Support constructor injection when using Spring with @qualifier. Real (unmocked) instance of the type which corresponds to the chosen qualifier, should satisfy the constructor of the tested class.

Currently this test fails:

public class ClassWithQualifiedSpringDependencyTest {
    @Tested(fullyInitialized = true)
    ClassWithQualifiedDependency tested;

    @BeforeClass
    public static void prepare() {
        Dependency.class.getName();
    }

    @Test
    public void testInjection() {
        assertNotNull(tested);
        assertNotNull(tested.getDependency());
        assertSame(tested.getDependency().getClass(), Dependency.class);
    }

    @Service
    public class ClassWithQualifiedDependency {
        private IDependency dependency;

        @Autowired
        public ClassWithQualifiedDependency(@Qualifier("commonDependency") IDependency d) {
            this.dependency = d;
        }

        public IDependency getDependency() {
            return dependency;
        }
    }

    public interface IDependency {
    }

    @Service("commonDependency")
    public class Dependency implements IDependency {
    }

    @Service("lessCommonDependency")
    public class Dependency2 implements IDependency {
    }
}

The following exception is thrown:

java.lang.IllegalArgumentException: No constructor in tested class that can be satisfied by available injectables
public ClassWithQualifiedSpringDependencyTest$ClassWithQualitfiedDependency(ClassWithQualifiedSpringDependencyTest,ClassWithQualifiedSpringDependencyTest$IDependency)
disregarded because parameter names are not available
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

@rliesenfeld

This comment has been minimized.

Copy link
Member

@rliesenfeld rliesenfeld commented Jun 13, 2016

@qualifier is already supported, but Spring's @Service/@Repository/@Component/@Controller/@primary is not.

However, I believe a better solution will be to improve the support for @tested object reuse. With that, the test class would be written as:

public class ClassWithQualifiedSpringDependencyTest {
    @Tested(fullyInitialized = true) Dependency commonDependency;
    @Tested(fullyInitialized = true) ClassWithQualifiedDependency tested;

    @Test
    public void testInjection() {
        assertNotNull(tested);
        assertNotNull(tested.getDependency());
        assertSame(tested.getDependency().getClass(), Dependency.class);
    }
}

... where the "commonDependency" tested object would be reused for the dependency in the other tested object. This already works, provided other classes implementing the interface haven't been loaded yet.

@rliesenfeld rliesenfeld self-assigned this Jun 13, 2016
@tuegeb

This comment has been minimized.

Copy link
Author

@tuegeb tuegeb commented Jun 13, 2016

Thanks, that sounds good. It is not always possible to control which implementation classes will be loaded before the test execution: It would be helpful, if the preferred implementation class could optionally be set via an attribute in the annotation. Example:

@Tested(fullyInitialized = true, 
        preferredClass = Dependency.class)
IDependency commonDependency;
@Tested(fullyInitialized = true)
ClassWithQualitfiedDependency tested;
@rliesenfeld

This comment has been minimized.

Copy link
Member

@rliesenfeld rliesenfeld commented Jun 13, 2016

You will be able to use the implementation class (Dependency) as the type for the @tested field, so this "preferredClass" attribute won't be necessary.

@tuegeb

This comment has been minimized.

Copy link
Author

@tuegeb tuegeb commented Jun 13, 2016

That is even better, as it is much more intuitive.

@tuegeb

This comment has been minimized.

Copy link
Author

@tuegeb tuegeb commented Jun 27, 2016

Many thanks for the implementation of this great enhancement.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
2 participants
You can’t perform that action at this time.