Spring 5 and JUNIT.

Let us try to put together some JUNITs with Spring 5 injection. One of the most challenging things of integrating JUnit and Spring was the role of the IDE. It is important to keep an eye on that. So here is the code we are going to look.

    @RunWith(SpringJUnit4ClassRunner.class)@ContextHierarchy({
        @ContextConfiguration(classes = StreamsConfig.class)})
        
    public class StreamsFilterSampleTest {
    
      Logger LOG = getLogger(StreamsFilterSampleTest.class);
    
      @Autowired
      StreamsFilterSample streamFilterStream;
      @Autowired
      StreamstoListSample streamstoListSample;

      @Test
      public void testStreamGroupBy() throws Exception {
        LOG.debug("Debugging method start ==> testStreamGroupBy " + "with parameter []");
        streamFilterStream.streamGroupBy();
        LOG.debug("Debugging method end ==> testStreamGroupBy " + "with parameter []");
      }
    }

We see the definition starts with Spring configuration initialization. The annotation

@RunWith(SpringJUnit4ClassRunner.class)@ContextHierarchy({
    @ContextConfiguration(classes = StreamsConfig.class)})

RunWith, we are annotating it to be Spring JUnit. The code block is getting initialized with configuration class of StreamConfig. Now let us take a look at the StreamConfig definition

    @Configuration()
    @ComponentScan("streams")
    public class StreamsConfig {
    public static final Logger LOG = LoggerFactory.getLogger(StreamsConfig.class);
    @Autowired
    StreamsFilterSample streamFilterStream;
      public StreamsConfig() {
        LOG.debug("Constructing Config");
    }
    }

We are autowiring an implementation class, StreamFilterSample. This is just a utility class and code goes something like this.

    public void streamGroupBy() {
    //3 apple, 2 banana, others 1
    List<Item> items = Arrays.asList(
        new Item(null, 10, new BigDecimal("20.00")),
        new Item("apple", 10, new BigDecimal("21.00")),
        new Item("apple", 10, new BigDecimal("22.00")),
        new Item("banana", 20, new BigDecimal("19.99")),
        new Item("orang", 10, new BigDecimal("29.99")),
        new Item("watermelon", 10, new BigDecimal("29.99")),
        new Item("papaya", 20, new BigDecimal("9.99")),
        new Item("apple", 10, new BigDecimal("9.99")),
        new Item("banana", 10, new BigDecimal("19.99")),
        new Item("apple", 20, new BigDecimal("9.99"))
    );
    //group by price
    Map<BigDecimal, List<Item>> groupByPriceMap =
     items.stream().collect(Collectors.groupingBy(Item::getPrice));
    Map<String, List<Item>> groupByNameMap =
        items.stream().filter(item -> item.getName() != null).collect(Collectors.groupingBy
            (Item::getName));
    System.out.println(groupByNameMap);
    }
    private static class Item {
    private String name;
    private int qty;
    private BigDecimal price;
    public Item(String name, int qty, BigDecimal price) {
      this.name = name;
      this.qty = qty;
      this.price = price;
    }
    public Item(String name, BigDecimal price) {this.name = name;this.price = price;}
    public int getQty() {return qty;}
    public void setQty(int qty) {this.qty = qty;}
    public BigDecimal getPrice() {return price;}
    public void setPrice(BigDecimal price) {this.price = price;}
    public String getName() {return name;}
    public void setName(String name) {this.name = name;}
    }

Now when we are running the JUnit, we have to make sure the @Test annotation is from the JUnit jar file. If you accidentally have the TestNG's @Test annotation, it will not be able to understand the configuration that we have in the JUnit header. Finally, remember to make sure the IDE is not making anything goofy where it pulled a wrong Annotation class. Here is a useful Stackoverflow discussion on this.