【问题标题】:Spring Cloud Stream Processor Unit Testing - @Autowire not workingSpring Cloud 流处理器单元测试 - @Autowire 不起作用
【发布时间】:2019-12-10 15:36:13
【问题描述】:

我正在尝试编写一个 spring 云流处理器 类,该类通过使用 @StreamListener(Processor.INPUT) 注释接收 XML

处理器然后提取较小的 XML 消息并通过this.processor.output().send(message); 将它们发送到输出 我还没有将它部署到 dataflow,因为我想用 junit 对其进行测试。当我用 junit 运行它时,我似乎无法让我的处理器对象实例化。

我尝试过使用@Autowired,这就是我在可能的示例中看到它的方式,但我似乎无法让它工作。任何想法,将不胜感激。

我的代码如下。

package io.spring.dataflow.sample.usagecostprocessor;

import java.io.File;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.cloud.stream.messaging.Processor;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Component;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import lombok.AllArgsConstructor;

@AllArgsConstructor
@EnableBinding(Processor.class)
public class REDACTXMLSplitter {


    private Processor processor;

    //@Autowired
    //private SendingBean sendingBean;

    @SuppressWarnings("unchecked")
    @StreamListener(Processor.INPUT)
    public void parseForREDACTApplications(String redactXML) {
        InputSource doc = new InputSource( new StringReader( redactXML ) );

        try
         {

                DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
                DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();

                DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
                factory.setNamespaceAware(true); // never forget this!

                XPathFactory xfactory = XPathFactory.newInstance();
                XPath xpath = xfactory.newXPath();

                String xpathQuery = "//REDACT/Application";

                xpath = xfactory.newXPath();
                XPathExpression query = xpath.compile(xpathQuery);
                NodeList productNodesFiltered = (NodeList) query.evaluate(doc, XPathConstants.NODESET);

                for (int i=0; i<productNodesFiltered.getLength(); ++i)
                {

                    Document suppXml = dBuilder.newDocument();

                    //we have to recreate the root node <products>
                    Element root = suppXml.createElement("REDACT"); 

                    Node productNode = productNodesFiltered.item(i);

                    //we append a product (cloned) to the new file
                    Node clonedNode = productNode.cloneNode(true);
                    suppXml.adoptNode(clonedNode); //We adopt the orphan :)
                    root.appendChild(clonedNode);

                    suppXml.appendChild(root);


                    //write out files
                    //At the end, we save the file XML on disk
//                      TransformerFactory transformerFactory = TransformerFactory.newInstance();
//                      Transformer transformer = transformerFactory.newTransformer();
//                      transformer.setOutputProperty(OutputKeys.INDENT, "yes");
//                      DOMSource source = new DOMSource(suppXml);
//                      StreamResult result =  new StreamResult(new File("test_" + i + ".xml"));
//                      transformer.transform(source, result);

                    TransformerFactory tf = TransformerFactory.newInstance();
                    Transformer transformer = tf.newTransformer();
                    transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
                    StringWriter writer = new StringWriter();
                    transformer.transform(new DOMSource(suppXml), new StreamResult(writer));
                    String output = writer.getBuffer().toString().replaceAll("\n|\r", "");

                    System.out.println(output);

                    Message<String> message = (Message<String>) suppXml;
                    this.processor.output().send(message);
                }

            }
         catch (XPathExpressionException | ParserConfigurationException | TransformerException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

package io.spring.dataflow.sample.usagecostprocessor;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


    @SpringBootApplication
    public class REDACTXMLSplitterApplication {
        public static void main(String[] args) {
            SpringApplication.run(REDACTXMLSplitterApplication.class, args);
        }
    }

package io.spring.dataflow.sample.usagecostprocessor;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.stream.messaging.Processor;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.util.ResourceUtils;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@DirtiesContext
public class MAIPXMLSplitterApplicationTests {


    @Autowired
    private Processor myProcessor;


    @Test
    public void contextLoads() {
    }

    @Test
    public void parseXML() {
            try {
                String cmErrorPayloadXML = readFile(ResourceUtils.getFile(this.getClass().getResource("/XMLSamples/REDACTApplicationXMLSamples/redact.xml")));
                REDACTXMLSplitter redactXMLSplitter = new REDACTXMLSplitter(myProcessor);
                redactXMLSplitter.parseForREDACTApplications(cmErrorPayloadXML);
            } catch (IOException e) {
                e.printStackTrace();
            }
    }


      public String readFile(File file) {
            StringBuffer stringBuffer = new StringBuffer();
            if (file.exists())
                try {
                    //read data from file
                    FileInputStream fileInputStream = new FileInputStream(file);
                    int c;
                    while ((c = fileInputStream.read()) != -1){
                        stringBuffer.append((char) c);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            return stringBuffer.toString();
        }

}

更新,

我试过了,但 myProcessor 仍然为空

package io.spring.dataflow.sample.usagecostprocessor;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.messaging.Processor;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.ResourceUtils;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = MAIPXMLSplitterApplicationTests.TestProcessor.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class MAIPXMLSplitterApplicationTests {


    @Autowired
    private Processor myProcessor;

    @Test
    public void contextLoads() {
    }

    @Test
    public void parseXML() {
            try {
                String cmErrorPayloadXML = readFile(ResourceUtils.getFile(this.getClass().getResource("/XMLSamples/MAIPApplicationXMLSamples/354_20191126_MAIP.xml")));
                MAIPXMLSplitter maipXMLSplitter = new MAIPXMLSplitter(myProcessor);
                maipXMLSplitter.parseForMAIPApplications(cmErrorPayloadXML);
            } catch (IOException e) {
                e.printStackTrace();
            }
    }


      public String readFile(File file) {
            StringBuffer stringBuffer = new StringBuffer();
            if (file.exists())
                try {
                    //read data from file
                    FileInputStream fileInputStream = new FileInputStream(file);
                    int c;
                    while ((c = fileInputStream.read()) != -1){
                        stringBuffer.append((char) c);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            return stringBuffer.toString();
        }

        @EnableBinding(Processor.class)
        @EnableAutoConfiguration
        public static class TestProcessor {

        }

}

【问题讨论】:

  • 尝试使用基于构造函数的注入,看看日志中是否有任何错误。 Spring 推荐基于构造函数的注入,所以尝试一下。

标签: spring junit autowired spring-cloud-stream spring-cloud-dataflow


【解决方案1】:

您需要在 Test 类使用的配置类之一中包含 @EnableBinding(Processor.class)

通常,您可以拥有一个简单的@Configuration 子类,并将其作为@SpringBootTest 类列表的一部分。可以看一个例子here

【讨论】:

  • 另外,如果您愿意升级到 3.0.0.RELEASE,您可以通过迁移到函数式编程模型来大大简化您的应用程序配置 - spring.io/blog/2019/10/14/…(更多内容在用户指南中)并使用一个新的测试框架cloud.spring.io/spring-cloud-static/spring-cloud-stream/…
  • @OlegZhurakousky 嗨 Oleg,我愿意发布 3.0.0。然而,通过查看 spring 博客链接,看起来他们正在简化功能以使用更少的注释。我相信我需要能够使用这条线......“this.processor.output().send(message);”因为一个输入可以有多个输出。我将如何在功能模型中实例化处理器?
  • 这一切都在本节中描述 - cloud.spring.io/spring-cloud-static/spring-cloud-stream/…。我们一直有BinderAwareChannelResolver,但现在我们也有spring.cloud.stream.sendto.destination
猜你喜欢
  • 1970-01-01
  • 2019-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-12
  • 2017-03-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多