使用 mockito 验证是否已记录带有 lambda 参数的错误
Verify with mockito that error with lambda arguments has been logged
我正在使用 log4j 作为记录器,并希望使用 lambda 作为日志消息的参数,以便在未启用特定日志级别的情况下延迟对消息的评估:
protected void appendAndSend(PcapPacket packet) {
...
if (packet.getWireLength() > snapShotLength) {
logger.error("{}: Received a packet with wire length {} larger than configured snapshot length {}",
() -> LOGGING_FILTER_TCP_ERROR,
() -> packet.getWireLength(),
() -> snapShotLength);
return;
}
...
}
在我的测试中,我想检查一条消息是否已写入错误日志
@Mock
Logger logger;
@Test
public void shouldLogErrorDueToBigPacketSize() {
packetFilter = ...;
PcapPacket packet = ...;
packetFilter.appendAndSend(packet);
verify(logger).error(startsWith("{}: Received a packet with wire length"), any(), any(), any());
}
但我找不到匹配 lambda 参数的方法。 any()
通配符不起作用。 Mockito 告诉我:
Wanted but not invoked:
logger.error(
startsWith("{}: Received a packet with wire length"),
<any>,
<any>,
<any>
);
-> at ...PacketFilterTest.shouldLogErrorDueToBigPacketSize(PacketFilterTest.java:143)
However, there were exactly 1 interaction with this mock:
logger.error(
"{}: Received a packet with wire length {} larger than configured snapshot length {}",
...PacketFilterImpl$$Lambda2/0x0000000100348828@47829d6d,
...PacketFilterImpl$$Lambda3/0x0000000100348a40@2f677247,
...PacketFilterImpl$$Lambda4/0x0000000100348c60@43f03c23
);
我可以使用什么来代替 any()
来匹配 lambda?
以下是显示问题的完整可运行示例 (gradle)
build.gradle:
plugins {
id 'java'
}
group 'org.example'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.apache.logging.log4j:log4j-core:2.13.3'
implementation 'junit:junit:4.13.1'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
testImplementation 'org.mockito:mockito-core:3.3.3'
}
test {
useJUnitPlatform()
}
Main.java
package org.example.lambdatest;
import org.apache.logging.log4j.Logger;
public class Main {
private final Logger logger;
public Main(Logger logger) {
this.logger = logger;
}
public void log(String text1, String text2, String text3) {
logger.error("This is my error text: {} {} {}", () -> text1, () -> text2, () -> text3);
}
}
MainTest.java:
package org.example.lambdatest;
import org.apache.logging.log4j.Logger;
import org.junit.jupiter.api.Test;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.startsWith;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
public class MainTest {
@Test public void testLogging() {
Logger logger = mock(Logger.class);
Main m = new Main(logger);
m.log("Something", "is", "wrong");
verify(logger).error(startsWith("This is"), any(), any(), any());
}
}
谢谢,
马丁
问题是将方法调用分派到 Logger
class 中的重载 error(...)
方法。
public class MainTest {
public static class Main {
private final Logger logger;
public Main(Logger logger) {
this.logger = logger;
}
public void log(String text1, String text2) {
// following call will reference error(String message, Supplier<?>... paramSuppliers) in Logger
logger.error("This is my error text: {} {}", () -> text1, () -> text2);
}
}
@Test public void testLogging() {
Logger logger = mock(Logger.class);
Main m = new Main(logger);
m.log("Something", "is wrong");
// following call will reference error(String message, Object p0, Object p1) in Logger
verify(logger).error(eq("This is my error text: {} {}"), any(), any());
}
}
由于它们将引用不同的方法,Mockito 会将其标记为不匹配。
该问题的一个解决方案是通过将 any()
个匹配器打包在一个数组中来帮助 java 分派到相同的重载 error(...)
方法:
public class MainTest {
public static class Main {
private final Logger logger;
public Main(Logger logger) {
this.logger = logger;
}
public void log(String text1, String text2) {
logger.error("This is my error text: {} {}", () -> text1, () -> text2);
}
}
@Test public void testLogging() {
Logger logger = mock(Logger.class);
Main m = new Main(logger);
m.log("Something", "is wrong");
verify(logger).error(eq("This is my error text: {} {}"), new Supplier[]{any(), any()});
}
}
现在对 error(...)
的两个方法调用将引用 Logger
中的相同方法
我正在使用 log4j 作为记录器,并希望使用 lambda 作为日志消息的参数,以便在未启用特定日志级别的情况下延迟对消息的评估:
protected void appendAndSend(PcapPacket packet) {
...
if (packet.getWireLength() > snapShotLength) {
logger.error("{}: Received a packet with wire length {} larger than configured snapshot length {}",
() -> LOGGING_FILTER_TCP_ERROR,
() -> packet.getWireLength(),
() -> snapShotLength);
return;
}
...
}
在我的测试中,我想检查一条消息是否已写入错误日志
@Mock
Logger logger;
@Test
public void shouldLogErrorDueToBigPacketSize() {
packetFilter = ...;
PcapPacket packet = ...;
packetFilter.appendAndSend(packet);
verify(logger).error(startsWith("{}: Received a packet with wire length"), any(), any(), any());
}
但我找不到匹配 lambda 参数的方法。 any()
通配符不起作用。 Mockito 告诉我:
Wanted but not invoked:
logger.error(
startsWith("{}: Received a packet with wire length"),
<any>,
<any>,
<any>
);
-> at ...PacketFilterTest.shouldLogErrorDueToBigPacketSize(PacketFilterTest.java:143)
However, there were exactly 1 interaction with this mock:
logger.error(
"{}: Received a packet with wire length {} larger than configured snapshot length {}",
...PacketFilterImpl$$Lambda2/0x0000000100348828@47829d6d,
...PacketFilterImpl$$Lambda3/0x0000000100348a40@2f677247,
...PacketFilterImpl$$Lambda4/0x0000000100348c60@43f03c23
);
我可以使用什么来代替 any()
来匹配 lambda?
以下是显示问题的完整可运行示例 (gradle)
build.gradle:
plugins {
id 'java'
}
group 'org.example'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.apache.logging.log4j:log4j-core:2.13.3'
implementation 'junit:junit:4.13.1'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
testImplementation 'org.mockito:mockito-core:3.3.3'
}
test {
useJUnitPlatform()
}
Main.java
package org.example.lambdatest;
import org.apache.logging.log4j.Logger;
public class Main {
private final Logger logger;
public Main(Logger logger) {
this.logger = logger;
}
public void log(String text1, String text2, String text3) {
logger.error("This is my error text: {} {} {}", () -> text1, () -> text2, () -> text3);
}
}
MainTest.java:
package org.example.lambdatest;
import org.apache.logging.log4j.Logger;
import org.junit.jupiter.api.Test;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.startsWith;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
public class MainTest {
@Test public void testLogging() {
Logger logger = mock(Logger.class);
Main m = new Main(logger);
m.log("Something", "is", "wrong");
verify(logger).error(startsWith("This is"), any(), any(), any());
}
}
谢谢, 马丁
问题是将方法调用分派到 Logger
class 中的重载 error(...)
方法。
public class MainTest {
public static class Main {
private final Logger logger;
public Main(Logger logger) {
this.logger = logger;
}
public void log(String text1, String text2) {
// following call will reference error(String message, Supplier<?>... paramSuppliers) in Logger
logger.error("This is my error text: {} {}", () -> text1, () -> text2);
}
}
@Test public void testLogging() {
Logger logger = mock(Logger.class);
Main m = new Main(logger);
m.log("Something", "is wrong");
// following call will reference error(String message, Object p0, Object p1) in Logger
verify(logger).error(eq("This is my error text: {} {}"), any(), any());
}
}
由于它们将引用不同的方法,Mockito 会将其标记为不匹配。
该问题的一个解决方案是通过将 any()
个匹配器打包在一个数组中来帮助 java 分派到相同的重载 error(...)
方法:
public class MainTest {
public static class Main {
private final Logger logger;
public Main(Logger logger) {
this.logger = logger;
}
public void log(String text1, String text2) {
logger.error("This is my error text: {} {}", () -> text1, () -> text2);
}
}
@Test public void testLogging() {
Logger logger = mock(Logger.class);
Main m = new Main(logger);
m.log("Something", "is wrong");
verify(logger).error(eq("This is my error text: {} {}"), new Supplier[]{any(), any()});
}
}
现在对 error(...)
的两个方法调用将引用 Logger