Apache Camel - 测试日志消息



我正在尝试测试使用from(x).to(y).log("SuccessKey123")onException(HttpOperationFailedException.class).log("ErrorKey123")的骆驼路线。

如何测试在成功处理消息时 Camel 是否记录"SuccessKey123",或者如果抛出 HttpOperationFailedException,则记录"ErrorKey123"?

我的路线生成器((:

@Component
public class myHttp4RouteBuilder extends SpringRouteBuilder {
public static final ID = "foo";
@Override
public void configure() throws Exception {
onException(HttpOperationFailedException.class)
.log("ErrorKey123")
.to(ERROR_QUEUE)
.handled(true);
from(AWS_SQS_ENDPOINT)
.to(REST_API_ENDPOINT)
.log("SuccessKey123");
}
}

测试类:

public class myHttp4RouteBuilderTest {
@Produce(uri = MOCK_ROUTE_FROM)
protected ProducerTemplate template;
@EndpointInject(uri = MOCK_ROUTE_TO)
private MockEndpoint mockEndpoint;
@Autowired
private CamelContext camelContext;
@Before
public void setup() throws Exception{
RouteDefinition rd = camelContext.getRouteDefinition(myHttp4RouteBuilder.ID);
rd.adviceWith(camelContext, new AdviceWithRouteBuilder() {
@Override
public void configure() throws Exception {
replaceFromWith(MOCK_ROUTE_FROM);
weaveByToUri(ERROR_QUEUE)
.replace()
.to(MOCK_ROUTE_TO);
}
});
}
@Test
@DirtiesContext
public void testSuccess() throws Exception {
// throw an HttpOperationFailedException
mockEndpoint.whenAnyExchangeReceived(new Processor() {
@Override
public void process(Exchange exchange) throws Exception {
throw new HttpOperationFailedException("Exception", 400, null, null, null, null);
}
});

//
//
// How can I test here that camel logs "ErrorKey123"
//
//

template.sendBody(MOCK_ROUTE_FROM, "some content");
mockEndpoint.assertIsSatisfied();
}
}

谢谢!

Camel使用slf4j,因此您只需在设置时将一些测试追加器添加到所需的记录器中,并检查之后记录的内容(甚至是模拟追加器接口(

我明白了;-(你把我放在正确的道路上。谢谢!

这是我的解决方案:

首先:创建自定义追加器

package de.example.test;
import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.AbstractAppender;
import org.apache.logging.log4j.core.appender.AppenderLoggingException;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
import org.apache.logging.log4j.core.config.plugins.PluginElement;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.core.layout.PatternLayout;
import org.slf4j.event.LoggingEvent;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

@Plugin(name="myAppenderForTesting", category="Core", elementType="appender", printObject=true)
public class MyAppenderForTesting extends AbstractAppender {
/** Here we collect all log messages */
public static List<LogEvent> logEvents = new ArrayList<>();
protected MyAppenderForTesting(String name, Filter filter, Layout<? extends Serializable> layout, final boolean ignoreExceptions) {
super(name, filter, layout, ignoreExceptions);
}
@PluginFactory
public static MyAppenderForTesting createAppender(
@PluginAttribute("name") String name,
@PluginElement("Layout") Layout<? extends Serializable> layout,
@PluginElement("Filter") final Filter filter,
@PluginAttribute("otherAttribute") String otherAttribute) {
return new MyAppenderForTesting(name, filter, layout, true);
}
@Override
public void append(LogEvent event) {
try {
logEvents.add(event);
} catch (Exception ex) {
if (!ignoreExceptions()) {
throw new AppenderLoggingException(ex);
}
} finally {
}
}
/**
* Clear log messages
*/
public static void clean() {
logEvents.clear();
}
}

简短解释:使用 append(( 方法,我们将每个日志事件添加到公共静态变量 logEvents 中。稍后在测试中,我们可以访问日志事件。

让这个追加器与 log4j 一起工作有点困难。就我而言,我在测试资源srctestresourceslog4j2.xml中创建了一个log4j2.xml

<?xml version="1.0" encoding="UTF-8" ?>
<Configuration packages="de.example">
<Appenders>
<myAppenderForTesting name="myAppenderForTesting">
<PatternLayout alwaysWriteExceptions="false" pattern="%d{dd.MM.yyyy HH:mm:ss} %-5p %t [%C{1}.%M:%L] %m %ex{10000}%n" />
</myAppenderForTesting>
</Appenders>
<Loggers>
<Root level="INFO">
<AppenderRef ref="myAppenderForTesting"/>
</Root>
</Loggers>
</Configuration>

在我的测试类中,我可以直接访问MyAppenderForTesting.logEvents。例如

for (LogEvent event : MyAppenderForTesting.logEvents) {
String message = event.getMessage().toString();
if (message.contains(search)) {
// do somethind
}
}

另一种方法是使用日志侦听器来收集消息并在之后断言它们:

// adding log listener
Set<String> logMessages = new HashSet<>();
((SpringBootCamelContext) camelContext)
.addLogListener((Exchange exchange, CamelLogger camelLogger, String message) -> {
logMessages.add(message);
return message;
});

// others test initializations...
// asserting the expected log message
assertThat(logMessages.stream()
.filter(m -> m.contains("looking for this message")).count()).isEqualTo(1);

您还可以使用 Camel 的建议,然后用模拟等模拟/替换这些日志端点,然后断言 Camel 根据您的操作将消息路由到这些端点。

  • http://camel.apache.org/advicewith.html

我同意克劳斯·易卜生的回答。您可以使用AdviceWithweaveByType(LogDefinition.class(.selectIndex(...(来精确定位您期望的日志记录。

旧线程,但它的可见性很高,所以我希望这个答案对某人有所帮助。

例如

@SpringBootTest
@CamelSpringBootTest
public class MyRouteTest {

@Autowired
protected CamelContext context;
@EndpointInject("mock:successRoute")
private MockEndpoint successRouteMockEndpoint;
@EndpointInject("mock:failRoute")
private MockEndpoint failRouteMockEndpoint;
...
@Test
public void Given_SuccessfulCall_ThenLogSuccess() throws Exception {
AdviceWith.adviceWith(context, myRouteId,
a -> a.weaveByType(LogDefinition.class).selectIndex(1).replace().to(successRouteMockEndpoint));
// directives to mock a successful response
successRouteMockEndpoint.expectedMessageCount(1);
failRouteMockEndpoint.expectedMessageCount(0);

// trigger route
successRouteMockEndpoint.assertIsSatisfied();
failRouteMockEndpoint.assertIsSatisfied();
}
@Test
public void Given_UnsuccessfulCall_ThenLogFailure() throws Exception {
AdviceWith.adviceWith(context, myRouteId,
a -> a.weaveByType(LogDefinition.class).selectIndex(0).replace().to(failRouteMockEndpoint));
// directives to mock an unsuccessful response
successRouteMockEndpoint.expectedMessageCount(0);
failRouteMockEndpoint.expectedMessageCount(1);

// trigger route
successRouteMockEndpoint.assertIsSatisfied();
failRouteMockEndpoint.assertIsSatisfied();
}
}

最新更新