在Java中将静态方法作为参数传递

时间:2019-03-13 12:40:45

标签: java testing junit mockito

你好,我正在测试具有某些验证方法的类,我一直在想是否有办法减少重复的代码。

@Test
void testCorrectEmailValidator() {
    List<String> correctEmails = Arrays.asList("test@test.com", "test123@test123.com", "test@test.com.in",
            "test.test2@test.com", "test.test2.test3@test.com", "TEST.2test@test.com");

    for (String email : correctEmails) {
        boolean isValid = UserCredentialsValidator.emailValidator(email);
        System.out.println("Email is valid: " + email + ": " + isValid);
        assertTrue(isValid);
    }
}

@Test
void testCorrectUsernameValidator() {
    List<String> correctUsernames = Arrays.asList("username", "123username", "username3", "user2name",
            "USERNAME", "USERNAME123", "123USERNAME123", "2uSERname33");

    for(String username : correctUsernames) {
        boolean isValid = UserCredentialsValidator.usernameValidation(username, userList);
        System.out.println("Username is valid:    " + username + "     : " + isValid);
        assertTrue(isValid);
    }
}

我也有用于其他字段(例如用户名等)的验证器。我正在考虑实现一个可以接受的辅助方法:将凭据测试为字符串,列表,但最后一个参数存在问题-验证方法,不确定如何通过。

我想用某种方法替换的代码是for循环。

4 个答案:

答案 0 :(得分:4)

恐怕您的考试质量低下。

应立即解决的问题包括

  1. UserCredentialsValidator.usernameValidation(username, userList);该方法不应使用第二个参数。对于API使用者,应该隐藏从中检索该列表的位置。

  2. List<String> correctEmails = Arrays.asList(...)List<String> correctUsernames = Arrays.asList(...)应该被删除。最好使用@ParameterizedTest@ValueSource对测试进行参数化。

  3. 我宁愿删除System.out.println语句。在测试中它们毫无意义。


@ParameterizedTest
@ValueSource(strings = {"test@test.com", "test123@test123.com"})
void testUserEmailValidationWithValidUserEmailShouldPass(String validUserEmail) {
    boolean isValid = UserCredentialsValidator.emailValidator(validUserEmail);
    assertTrue(isValid);
}

@ParameterizedTest
@ValueSource(strings = {"username", "123username"})
void testUserNameValidationWithValidUserNameShouldPass(String validUserName) {
    boolean isValid = UserCredentialsValidator.usernameValidation(validUserName);
    assertTrue(isValid);
}

现在没有什么可以减少的了。

答案 1 :(得分:0)

您正在努力测试的事实表明设计气味

现在是您在这里探索strategy design pattern的好时机。

基本上,您的主代码类似于

interface IValidator {
     boolean isValid(List<String> yourDataToBeValidated);
}

现在为电子邮件,用户名等不同字段创建多个验证器类。

class EmailValidator implements IValidator {
      boolean isValid(List<String> yourDataToBeValidated){
         //Email specific validations goes here
      }
}

您可以随时随地创建更多验证器。

现在在您的单元测试中创建new EmailValidator()new UsernameValidator()并将您的emailIdsusernames设为isValid()方法,如下所示:

    boolean isValid = new EmailValidator().isValid(Arrays.asList("test@test.com", "test123@test123.com");
    assertTrue(isValid);

答案 2 :(得分:0)

正如我在对您的问题的评论中已经指出的那样,我不确定重新排列您的代码是否会有所帮助。但是,作为比较,这是使用通用方法的Java8 +版本:

@Test
void testCorrectEmailValidator() {
  List<String> correctEmails = Arrays.asList("test@test.com", "test123@test123.com", "test@test.com.in",
          "test.test2@test.com", "test.test2.test3@test.com", "TEST.2test@test.com");

  testValidator( "Email", correctEmails , email -> UserCredentialsValidator.emailValidator(email) );
}

@Test
void testCorrectUsernameValidator() {
  List<String> correctUsernames = Arrays.asList("username", "123username", "username3", "user2name",
        "USERNAME", "USERNAME123", "123USERNAME123", "2uSERname33");

  //I don't know where userList does come from but it would need to be final to be used here
  testValidator( "Username", correctUsernames, username -> UserCredentialsValidator.usernameValidation(username, userList) );
}

void testValidator( String name, List<String> data, Predicate<String> validator) {
  for( String element : data ) {
    boolean isValid = validator.test( element );
    System.out.println( name + " is valid:    " + element + "     : " + isValid);
    assertTrue(isValid);
  }
}

在这种情况下,两种方法都需要23行,而第二种方法可能更易于重用,但难于理解且缺乏灵活性(例如,如果您需要传递其他参数等)

答案 3 :(得分:0)

使用参数化测试:

static Stream<String> emailsSource() {
    return Stream.of("test@test.com", "test123@test123.com", "test@test.com.in",
        "test.test2@test.com", "test.test2.test3@test.com", "TEST.2test@test.com");
}

@Test
@MethodSource("emailsSource")
void testCorrectEmailValidator(String email) {
    boolean isValid = UserCredentialsValidator.emailValidator(email);
    assertTrue(isValid);
}

重复usernameSource等。恕我直言,这足以消除重复。

但是,如果您想进一步推广它,请使用方法引用。我不推荐它。

static Stream<Pair<String,Predicate<String>>> allSources() {
    return Stream.of(
        Pair.of("test@test.com", UserCredentialsValidator::emailValidator),
        Pair.of("username", UserCredentialsValidator::usernameValidationOneArg), // like usernameValidation but with argument userList fixed
        ...
    );
}

@Test
@MethodSource("allSources")
void testAll(Pair<String,Predicate<String>> p) {
    String s = p.getLeft();
    Predicate<String> test = p.getRight();
    boolean isValid = test.apply(email);
    assertTrue(isValid);
}