在我以前的文章中,我展示了有关JavaBeans单元测试的一些技巧。 在此博客文章中,我将提供有关单元测试某些相当常见的Java代码的另外两个技巧,即实用程序类和Log4J日志记录语句 。
测试实用程序类
如果您的实用程序类遵循与我倾向于编写的相同的基本设计,则它们由带有私有构造函数和所有静态方法的最终类组成。
实用类测试仪
package it.jdev.example;
import static org.junit.Assert.*;
import java.lang.reflect.*;
import org.junit.Test;
/**
* Tests that a utility class is final, contains one private constructor, and
* all methods are static.
*/
public final class UtilityClassTester {
private UtilityClassTester() {
super();
}
/**
* Verifies that a utility class is well defined.
*
* @param clazz
* @throws Exception
*/
@Test
public static void test(final Class<?> clazz) throws Exception {
// Utility classes must be final.
assertTrue("Class must be final.", Modifier.isFinal(clazz.getModifiers()));
// Only one constructor is allowed and it has to be private.
assertTrue("Only one constructor is allowed.", clazz.getDeclaredConstructors().length == 1);
final Constructor<?> constructor = clazz.getDeclaredConstructor();
assertFalse("Constructor must be private.", constructor.isAccessible());
assertTrue("Constructor must be private.", Modifier.isPrivate(constructor.getModifiers()));
// All methods must be static.
for (final Method method : clazz.getMethods()) {
if (!Modifier.isStatic(method.getModifiers()) && method.getDeclaringClass().equals(clazz)) {
fail("Non-static method found: " + method + ".");
}
}
}
}
该UtilityClassTester本身也遵循上面提到的实用程序类约束,因此有什么更好的方法通过使用它来测试自身来证明其用途:
UtilityClassTester的测试用例
package it.jdev.example;
import org.junit.Test;
public class UtilityClassTesterTest {
@Test
public void test() throws Exception {
UtilityClassTester.test(UtilityClassTester.class);
}
}
测试Log4J记录事件
调用声明异常的方法时,您将重新声明该异常,或者尝试在try-catch块中对其进行处理。 在后一种情况下,至少要做的是记录捕获的异常。 下面是一个非常简单的示例:
MyService示例
package it.jdev.example;
import java.lang.invoke.MethodHandles;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class MyService {
private static final Logger LOGGER = Logger.getLogger(MethodHandles.Lookup.class);
@Autowired
private MyRepository myRepository;
public void doSomethingUseful() {
try {
myRepository.doSomethingVeryUseful();
} catch (SomeException e) {
LOGGER.error("Some very informative error logging.", e);
}
}
}
当然,您将需要测试是否正确记录了异常。 遵循以下内容:
MyService日志记录事件的测试用例
package it.jdev.example;
import static org.junit.Assert.*;
import org.apache.log4j.spi.LoggingEvent;
import org.junit.*;
import org.mockito.*;
public class MyServiceTest {
@Mock
private MyRepository myRepository;
@InjectMocks
private MyService myService = new MyService();
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
@Test
public void thatSomeExceptionIsLogged() throws Exception {
TestAppender testAppender = new TestAppender();
Mockito.doThrow(SomeException.class).when(myRepository).doSomethingVeryUseful();
myService.doSomethingUseful();
assertTrue(testAppender.getEvents().size() == 1);
final LoggingEvent loggingEvent = testAppender.getEvents().get(0);
assertEquals("Some very informative error logging.", loggingEvent.getMessage().toString());
}
}
但是,如何实现这一目标呢? 事实证明,将新的LogAppender添加到Log4J RootLogger非常容易。
用于Log4J的TestAppender
package it.jdev.example;
import java.util.*;
import org.apache.log4j.*;
import org.apache.log4j.spi.*;
/**
* Utility for testing Log4j logging events.
* <p>
* Usage:<br />
* <code>
* TestAppender testAppender = new TestAppender();<br />
* classUnderTest.methodThatWillLog();<br /><br />
* LoggingEvent loggingEvent = testAppender.getEvents().get(0);<br /><br />
* assertEquals()...<br /><br />
* </code>
*/
public class TestAppender extends AppenderSkeleton {
private final List<LoggingEvent> events = new ArrayList<LoggingEvent>();
public TestAppender() {
this(Level.ERROR);
}
public TestAppender(final Level level) {
super();
Logger.getRootLogger().addAppender(this);
this.addFilter(new LogLevelFilter(level));
}
@Override
protected void append(final LoggingEvent event) {
events.add(event);
}
@Override
public void close() {
}
@Override
public boolean requiresLayout() {
return false;
}
public List<LoggingEvent> getEvents() {
return events;
}
/**
* Filter that decides whether to accept or deny a logging event based on
* the logging level.
*/
protected class LogLevelFilter extends Filter {
private final Level level;
public LogLevelFilter(final Level level) {
super();
this.level = level;
}
@Override
public int decide(final LoggingEvent event) {
if (event.getLevel().isGreaterOrEqual(level)) {
return ACCEPT;
} else {
return DENY;
}
}
}
}
翻译自: https://www.javacodegeeks.com/2014/09/some-more-unit-test-tips.html