【问题标题】:Java NegativeTest private method with Reflection to catch custom ApplicationException带有反射的 Java NegativeTest 私有方法来捕获自定义 ApplicationException
【发布时间】:2020-03-26 06:16:32
【问题描述】:

所以我正在使用模拟数据库层测试 AccountService 类。 在这个 AccountService 类中,有一个私有方法可以根据正则表达式检查从 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 功能,因为它是一个学校项目)。

非常感谢!

【问题讨论】:

    标签: java testing junit reflection private


    【解决方案1】:

    感谢 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 接口的好处和优雅,但是我还不具备掌握它的复杂性的知识。所以我会坚持这个测试,我可以在口语考试中解释。

    【讨论】:

      【解决方案2】:

      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));
      }
      

      【讨论】:

        猜你喜欢
        • 2013-04-23
        • 1970-01-01
        • 2022-11-27
        • 1970-01-01
        • 2013-02-25
        • 2012-04-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多