在我以前的文章中,我展示了有关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*/@Testpublic 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 {@Testpublic 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);@Autowiredprivate 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 {@Mockprivate MyRepository myRepository;@InjectMocksprivate MyService myService = new MyService();@Beforepublic void setup() {MockitoAnnotations.initMocks(this);}@Testpublic 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));}@Overrideprotected void append(final LoggingEvent event) {events.add(event);}@Overridepublic void close() {}@Overridepublic 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;}@Overridepublic 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