简体   繁体   中英

@Qualifier does not work within Junit4

I try to improve my Spring knowledge by reading Spring in action 4. When I've to to section, describing using of Qualifier annotation (3.3.2), i faced the problem. To test this annotation in action, I wrote Dessert interface, which is implemented by 3 classes, creating in context using @Component annotation. I also created class Taster, which "tastes" some dessert, autowired into by some qualifier. When I run my application, using AnnotationConfigApplicationContext - everything works good. With SpringJUnit4ClassRunner - it does not. I guess I miss something in my test code, but I do not have enough knowledge to realize what. Interface:

package bakery.intrface;
@FunctionalInterface
public interface Dessert {
    void introduce();
}

Cake:

package bakery.desserts;

import bakery.intrface.Dessert;
import org.springframework.stereotype.Component;

@Component
public class Cake implements Dessert {
    @Override
    public void introduce() {
        System.out.println("I am a cake!");
    }
}

Cookie:

package bakery.desserts;

import bakery.intrface.Dessert;
import org.springframework.stereotype.Component;

@Component
public class Cookie implements Dessert {
    @Override
    public void introduce() {
        System.out.println("I'm a cookie!");
    }
}

Ice cream:

package bakery.desserts;

import bakery.intrface.Dessert;
import org.springframework.stereotype.Component;

@Component
public class IceCream implements Dessert {
    @Override
    public void introduce() {
        System.out.println("I'm an ice cream!");
    }
}

The class, consumes some bean, Taster:

package bakery;

import bakery.intrface.Dessert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component
public class Taster {

    private Dessert dessert;

    public void taste(){
        dessert.introduce();
    }

    @Autowired
    @Qualifier("iceCream")
    public void setDessert(Dessert dessert) {
        this.dessert = dessert;
    }
}

Configuration:

package bakery.config;

import bakery.Bakery;
import bakery.Taster;
import bakery.desserts.Cake;
import bakery.intrface.Dessert;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;

@ComponentScan(basePackageClasses = Bakery.class)
public class BakeryConfig {
}

Run class:

package bakery;

import bakery.config.BakeryConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Bakery {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BakeryConfig.class);
        String[] beans  = context.getBeanDefinitionNames();
        Taster taster = (Taster) context.getBean("taster");
        taster.taste();
    }
}

Test class:

package bakery;

import bakery.config.BakeryConfig;
import bakery.intrface.Dessert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import static org.junit.Assert.assertNotNull;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = BakeryConfig.class)
public class BakeryTest {

    @Autowired
    Dessert dessert;

    @Autowired
    Taster taster;

    @Test
    public void contextInit(){
        assertNotNull(dessert);
        dessert.introduce();
    }

    @Test
    public void tasterInit(){
        assertNotNull(taster);
    }
}

When I run the test, I'm getting the exception: No qualifying bean of type [bakery.intrface.Dessert] is defined: expected single matching bean but found 3: cookie,iceCream,cake.

There are 3 "Dessert" beans in your application context, you have to specify which one you want to wire.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = BakeryConfig.class)
public class BakeryTest {

    @Autowired
    @Qualifier("iceCream")  // <===================== you must specify which bean to be wired
    Dessert dessert;

    @Autowired
    Taster taster;

This is to be expected.

The declaration

@Autowired
Dessert dessert;

is asking for a Dessert object. Dessert is the interface, and there are three implementing classes, Cookie , IceCream , and Cake . Since you haven't made it more explicit which of those implementations you want, Spring throws an error because it can't decide what to do.

If you need this in your test, you can do one of the following:

@Autowired
@Qualifier("iceCream")
Dessert dessert;

to get only the ice cream dessert,

OR

@Autowired
List<Dessert> desserts;

to get a list containing all the implementations.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM