Java 使用反射捕获自定义 ApplicationException 的 NegativeTest 私有方法
Java NegativeTest private method with Reflection to catch custom ApplicationException
因此,我正在使用模拟数据库层测试 AccountService class。
在此 AccountService class 中,有一个私有方法根据正则表达式检查从 UI 收到的输入。
我写的正面测试工作正常:
@Test
public void testEmailPatroonCorrect() throws Exception{
//Correcte emails
List<String> emails = new ArrayList<>();
emails.add("user@domain.com");
emails.add("user@domain.co.in");
emails.add("user.name@domain.com");
emails.add("user_name@domain.com");
emails.add("username@yahoo.corporate.in");
Class<AccountService> foo = AccountService.class;
Method method = foo.getDeclaredMethod("checkEmailPatroon", String.class);
method.setAccessible(true);
assertThatCode(() -> {
for(String email : emails){
method.invoke(AccountService,email);
}}).doesNotThrowAnyException();
}
然而,为了简单起见,即使列表中只有一个对象,但对于负面测试(包含错误电子邮件模式的列表)
@Test
public void testEmailPatroonFout() throws Exception{
//Verkeerde emailpatronen
List<String> emails = new ArrayList<>();
emails.add(".username@yahoo.com");
Class<AccountService> foo = AccountService.class;
Method method = foo.getDeclaredMethod("checkEmailPatroon", String.class);
method.setAccessible(true);
assertThatThrownBy(()->{
for(String email : emails){
method.invoke(AccountService,email);
}
}).isInstanceOf(ApplicationException.class).hasMessage(ApplicationExceptionType.ONGELDIGE_EMAIL.getMsg());
}
测试时抛出的异常为:java.lang.reflect.InvocationTargetException。在应用程序中,ApplicationException 被捕获得很好。
问题是如何为错误的电子邮件模式列表编写适当的测试? (不使用 @VisibleForTesting 功能,因为它是一个学校项目)。
非常感谢!
InvocationTargetException
包装反射调用方法中抛出的异常。所以你可以捕获 InvocationTargetException
并重新抛出它的原因,但我会把它放到一个实用方法中,比如
public interface TestMethod<D,A> {
void invoke(D d, A a) throws Throwable;
}
static <D,A> TestMethod<D,A> method(
Class<D> declarer, String name, Class<A> argType) throws ReflectiveOperationException {
Method method = declarer.getDeclaredMethod(name, argType);
method.setAccessible(true);
return (d,a) -> {
try {
method.invoke(d, a);
} catch(InvocationTargetException ex) {
throw ex.getTargetException();
}
};
}
你可以像这样使用
@Test
public void testEmailPatroonFout() throws Exception{
//Verkeerde emailpatronen
List<String> emails = new ArrayList<>();
emails.add(".username@yahoo.com");
TestMethod<AccountService, String> method
= method(AccountService.class, "checkEmailPatroon", String.class);
assertThatThrownBy(() -> {
for(String email : emails){
method.invoke(AccountService, email);
}
}).isInstanceOf(ApplicationException.class)
.hasMessage(ApplicationExceptionType.ONGELDIGE_EMAIL.getMsg());
}
TestMethod
接口的形状允许像
这样的替代实现
static <D,A> TestMethod<D,A> method(
Class<D> declarer, String name, Class<A> argType) throws ReflectiveOperationException {
Method method = declarer.getDeclaredMethod(name, argType);
method.setAccessible(true);
return MethodHandleProxies.asInterfaceInstance(
TestMethod.class, MethodHandles.lookup().unreflect(method));
}
感谢 Holger,我能够为此目的编写一个工作测试。
@Test
public void testEmailPatroonFoutLoop() throws Throwable {
//Verkeerde emailpatronen
List<String> wrongEmails = new ArrayList<>();
wrongEmails.add(".username@yahoo.com");
wrongEmails.add("username@yahoo.com.");
wrongEmails.add("usernameyahoo.com");
wrongEmails.add("username@yahoo.c");
wrongEmails.add("use..rname@yahoo.com");
Class<AccountService> foo = AccountService.class;
Method method = foo.getDeclaredMethod("checkEmailPatroon", String.class);
method.setAccessible(true);
int countedWrongEmails = 0;
for(String email : wrongEmails){
try{
method.invoke(accServ,email);
}
catch (InvocationTargetException ie){
Exception e = (Exception) ie.getTargetException();
if(e.getMessage().equals(ApplicationExceptionType.ONGELDIGE_EMAIL.getMsg())){
countedWrongEmails++;
}
}
}
assertThat(countedWrongEmails).isEqualTo(wrongEmails.size());
}
虽然我看到了编写 TestMethod 接口的好处和优雅,但是我还不具备掌握它的复杂性的知识。所以我会坚持这个我可以在口语考试中解释的测试。
因此,我正在使用模拟数据库层测试 AccountService class。 在此 AccountService class 中,有一个私有方法根据正则表达式检查从 UI 收到的输入。
我写的正面测试工作正常:
@Test
public void testEmailPatroonCorrect() throws Exception{
//Correcte emails
List<String> emails = new ArrayList<>();
emails.add("user@domain.com");
emails.add("user@domain.co.in");
emails.add("user.name@domain.com");
emails.add("user_name@domain.com");
emails.add("username@yahoo.corporate.in");
Class<AccountService> foo = AccountService.class;
Method method = foo.getDeclaredMethod("checkEmailPatroon", String.class);
method.setAccessible(true);
assertThatCode(() -> {
for(String email : emails){
method.invoke(AccountService,email);
}}).doesNotThrowAnyException();
}
然而,为了简单起见,即使列表中只有一个对象,但对于负面测试(包含错误电子邮件模式的列表)
@Test
public void testEmailPatroonFout() throws Exception{
//Verkeerde emailpatronen
List<String> emails = new ArrayList<>();
emails.add(".username@yahoo.com");
Class<AccountService> foo = AccountService.class;
Method method = foo.getDeclaredMethod("checkEmailPatroon", String.class);
method.setAccessible(true);
assertThatThrownBy(()->{
for(String email : emails){
method.invoke(AccountService,email);
}
}).isInstanceOf(ApplicationException.class).hasMessage(ApplicationExceptionType.ONGELDIGE_EMAIL.getMsg());
}
测试时抛出的异常为:java.lang.reflect.InvocationTargetException。在应用程序中,ApplicationException 被捕获得很好。 问题是如何为错误的电子邮件模式列表编写适当的测试? (不使用 @VisibleForTesting 功能,因为它是一个学校项目)。
非常感谢!
InvocationTargetException
包装反射调用方法中抛出的异常。所以你可以捕获 InvocationTargetException
并重新抛出它的原因,但我会把它放到一个实用方法中,比如
public interface TestMethod<D,A> {
void invoke(D d, A a) throws Throwable;
}
static <D,A> TestMethod<D,A> method(
Class<D> declarer, String name, Class<A> argType) throws ReflectiveOperationException {
Method method = declarer.getDeclaredMethod(name, argType);
method.setAccessible(true);
return (d,a) -> {
try {
method.invoke(d, a);
} catch(InvocationTargetException ex) {
throw ex.getTargetException();
}
};
}
你可以像这样使用
@Test
public void testEmailPatroonFout() throws Exception{
//Verkeerde emailpatronen
List<String> emails = new ArrayList<>();
emails.add(".username@yahoo.com");
TestMethod<AccountService, String> method
= method(AccountService.class, "checkEmailPatroon", String.class);
assertThatThrownBy(() -> {
for(String email : emails){
method.invoke(AccountService, email);
}
}).isInstanceOf(ApplicationException.class)
.hasMessage(ApplicationExceptionType.ONGELDIGE_EMAIL.getMsg());
}
TestMethod
接口的形状允许像
static <D,A> TestMethod<D,A> method(
Class<D> declarer, String name, Class<A> argType) throws ReflectiveOperationException {
Method method = declarer.getDeclaredMethod(name, argType);
method.setAccessible(true);
return MethodHandleProxies.asInterfaceInstance(
TestMethod.class, MethodHandles.lookup().unreflect(method));
}
感谢 Holger,我能够为此目的编写一个工作测试。
@Test
public void testEmailPatroonFoutLoop() throws Throwable {
//Verkeerde emailpatronen
List<String> wrongEmails = new ArrayList<>();
wrongEmails.add(".username@yahoo.com");
wrongEmails.add("username@yahoo.com.");
wrongEmails.add("usernameyahoo.com");
wrongEmails.add("username@yahoo.c");
wrongEmails.add("use..rname@yahoo.com");
Class<AccountService> foo = AccountService.class;
Method method = foo.getDeclaredMethod("checkEmailPatroon", String.class);
method.setAccessible(true);
int countedWrongEmails = 0;
for(String email : wrongEmails){
try{
method.invoke(accServ,email);
}
catch (InvocationTargetException ie){
Exception e = (Exception) ie.getTargetException();
if(e.getMessage().equals(ApplicationExceptionType.ONGELDIGE_EMAIL.getMsg())){
countedWrongEmails++;
}
}
}
assertThat(countedWrongEmails).isEqualTo(wrongEmails.size());
}
虽然我看到了编写 TestMethod 接口的好处和优雅,但是我还不具备掌握它的复杂性的知识。所以我会坚持这个我可以在口语考试中解释的测试。