2012-01-11 42 views
8

Giả sử tôi có các đối tượng dịch vụ sau đâykiểm tra hành vi của khoảng trống phương pháp

public class UserService { 

    @Autowired 
    private UserDao dao; 

    public void addUser(String username, String password) { 
     if (username.length() < 8) { 
      username = username + "random" ; // add some random string 
     } 
     User user = new User(username, password); 

     dao.save(user); 
    } 
} 

Tôi muốn thử nghiệm hành vi của các phương pháp "adduser" khi chiều dài tên người dùng là ít 8 và khi tên người dùng là hơn 8 char . Làm thế nào để tiếp cận trong thử nghiệm đơn vị UserService.addUser (...), và xác minh nó? Tôi biết sử dụng assert(), nhưng giá trị "mật khẩu" không có sẵn bên ngoài phương thức addUser (...).

Tôi sử dụng JUnit và Mockito.

Trả lời

6

Tôi đã đưa ra giải pháp sau khi một số người truy cập lại vấn đề sau một vài tháng.

Ý tưởng là quan sát đối tượng người dùng đang được chuyển đến UserDao. Chúng ta có thể kiểm tra giá trị của tên người dùng bằng cách làm này, vì thế mà đơn vị mã kiểm tra:

@RunWith(MockitoJUnitRunner.class) 
public class UserServiceTest { 
    @Mock 
    private UserDao dao; 

    @InjectMock 
    private UserService service; 

    @Test 
    public void testAddingUserWithLessThan8CharUsername() { 
     final String username = "some"; 
     final String password = "user"; 
     doAnswer(new Answer<Object>() { 
      @Override 
      public Object answer(InvocationOnMock invocationOnMock) throws Throwable { 
       Object[] args = invocationOnMock.getArguments(); 
       User toBeSaved = (User) args[0]; 
       Assert.assertEquals(username + "random", toBeSaved.getPassword()); 
       return null; 
      } 
     }).when(userDao).save(Matchers.any(User.class)); 
     service.addUser(username, password); 
    } 
} 

Guillaume thực sự đã có câu trả lời gần nhất, nhưng ông trả lời bằng các JMock. Tuy nhiên, anh ấy đã cho tôi ý tưởng về cách thực hiện điều này, vì vậy tôi nghĩ anh ấy cũng xứng đáng nhận được một số tín dụng.

-1

Cách dễ nhất là để trích xuất các phần, nơi bạn có tên người dùng chỉnh lý

if (username.length() < 8) { 
    username = username + "random" ; // add some random string 
} 

vào một phương pháp và kiểm tra giá trị trả về của phương thức đó.

public string GetValidUsername(string userName){ 
    if (username.length() < 8) { 
     return username + "random" ; // add some random string 
    } 
    return username; 
} 

với điều này bạn có thể chuyển các loại tên người dùng khác nhau và kiểm tra hành vi mã của bạn.

+0

Tôi đã nghĩ về điều này, nhưng trường hợp thực tế được tạo thành bằng nhiều phương pháp rồi. Những gì tôi đã viết ở đây là phiên bản đơn giản hơn của trường hợp thực tế. –

+0

Mặc dù có giá trị âm. Tôi vẫn nghĩ rằng nó sẽ làm cho mọi thứ đơn giản hơn để kiểm tra xác thực tên người dùng và logic sửa đổi trong sự cô lập (tách biệt với những gì được truyền vào phương thức lưu). Thậm chí nhiều hơn như vậy, nếu logic đó có phức tạp khác. Và tôi cũng nghĩ rằng bạn sẽ không cần phải sử dụng bất kỳ chế giễu nào để thử nghiệm logic đó. – derdo

1

Bạn đang thử nghiệm các tác dụng phụ, nhưng may thay, mọi thứ bạn cần được chuyển đến dao.save(). Đầu tiên, tạo UserDao (có hoặc không có Mockito), sau đó bạn có thể sử dụng ReflectionTestUtils để đặt dao trong UserService, sau đó bạn có thể kiểm tra các giá trị được chuyển đến dao.save().

Cái gì như:

private class TestUserDao extends UserDao { 
    private User savedUser; 
    public void save(User user) { 
     this.savedUser = user; 
    } 
} 

@Test public void testMethod() { 
    UserService userService = new UserService(); 
    TestUserDao userDao = new TestUserDao(); 

    ReflectionTestUtils.setField(userService, "dao", userDao); 

    userService.addUser("foo", "bar"); 

    assertEquals("foo", userDao.savedUser.username.substring(0, 3)); 
    assertEquals("bar", userDao.savedUser.password); 
} 

Hoặc bạn có thể sử dụng Mockito để thử ra người Dao nếu bạn muốn.

+0

Đây không phải là Mock, đây là một Stub. Kiểm tra xem: http://martinfowler.com/articles/mocksArentStubs.html – Guillaume

+0

Vâng, tôi biết, nhưng tôi đã sử dụng cùng một thuật ngữ như OP. Tôi đã thay đổi văn bản. –

+0

Tôi đã thử phương pháp này, sử dụng Mockito để giả lập đối tượng UserDao. Thật không may, ReflectionTestUtils luôn trả về một đối tượng userDao null. Đã làm điều gì sai? –

0

Tất cả sẽ phụ thuộc vào cách thức lưu DAO của bạn được triển khai.

Nếu bạn đang thực sự lưu trữ đến một kho lưu trữ mã hóa cứng, sau đó có thể bạn sẽ cần phải truy vấn các kho riêng của mình cho các giá trị bạn đang intereseted trong.

Nếu bạn có một giao diện cơ bản mà được gọi, sau đó bạn sẽ có thể thiết lập phương thức gọi lại và truy xuất giá trị thực đang được lưu.

Tôi chưa bao giờ sử dụng Mockito vì vậy tôi không thể cung cấp cho bạn mã chính xác mà làm bài viết này nên giải quyết rằng:

Using Mockito, how do I intercept a callback object on a void method?

0

xem xét giải nén tên người dùng thế hệ logic như sự phụ thuộc từ UserService.

interface UserNameGenerator { 
    Strign generate(); 
} 

Dây UserNameGenerator giống như UserDao. Và thay đổi mã thành:

public class UserService { 

    @Autowired 
    private UserDao dao; 
    @Autowired 
    private UserNameGenerator nameGenerator; 

    public void addUser(String username, String password) { 
     if (username.length() < 8) { 
      username = nameGenerator.generate(); 
     } 
     User user = new User(username, password); 

     dao.save(user); 
    } 
} 

Tiếp theo hãy tạo triển khai mặc định là UserNameGenerator và di chuyển tên tạo logic tại đó.

Bây giờ bạn có thể dễ dàng kiểm tra hành vi bằng cách chế nhạo UserNameGeneratorUserDao.

Để kiểm tra trường hợp sử dụng khi username là chiều dài được ít hơn 8

String username = "123"; 
String password = "pass"; 

String generatedName = "random"; 

// stub generator 
when(nameGenerator.generate()).thenReture(generatedName); 

// call the method 
userService.addUser(username, password); 

// verify that generator was called 
verify(nameGenerator).generate(); 

verify(userDao).save(new User(generatedName, password)); 

Để kiểm tra trường hợp sử dụng khi username là chiều dài lớn hơn 8

String username = "123456789"; 
String password = "pass"; 

String generatedName = "random"; 

// call the method 
userService.addUser(username, password); 

// verify that generator was never called 
verify(nameGenerator, never()).generate(); 

verify(userDao).save(new User(username, password)); 
1

Sử dụng một khuôn khổ mocking . Ví dụ dưới đây sử dụng JMock2, nhưng nó sẽ tương tự với EasyMock, Mockito, v.v. Ngoài ra, bạn cần trích xuất tạo tên người dùng thành một cái gì đó như UsernameGenmerator để có thể giả lập nó. Bạn cần một thử nghiệm cụ thể khác cho trình tạo tên người dùng.

private final Mockery mockery = new Mockery(); 
private final UserDao mockDao = mockery.mock(UserDao.class); 
private final UsernameGenerator mockUserNameGenerator = mockery.mock(UsernameGenerator.class); 

@Test 
public void addUserUsesDaoToSaveUser() { 
    final String username = "something"; 
    final String generatedUsername = "siomething else"; 
    final String password = "a password"; 
    mockery.checking(new Expectations() {{ 
     oneOf(mockUsernameGenerator).generateUsername(username); 
     will(returnValue(generatedUsername)); 
     oneOf(mockDao).save(new User(generatedUsername, password)); // assumes your User class has a "natueral" equals/hashcode 
    }}); 

    UserService userService = new UserService(); 
    userService.addUser(username, password); 
} 

Và đối với UsernameGenerator bạn cần thử nghiệm trên chiều dài của tên người dùng quay trở lại:

@Test 
public void leavesUsernameUnchangedIfMoreThanEightChars() { 
    final String username = "123456789"; 
    final UsernameGenerator usernameGenerator = new UsernameGenerator(); 
    assertEquals(username, userGenerator.generateUsername(username)); 
} 

@Test 
public void addsCharactersToUsernameIfLessThanEightChars() { 
    final String username = "1234567"; 
    final UsernameGenerator usernameGenerator = new UsernameGenerator(); 
    assertEquals(8, userGenerator.generateUsername(username).length()); 
} 

Tất nhiên, tùy thuộc vào phương pháp "ngẫu nhiên" của bạn, bạn có thể muốn kiểm tra hành vi cụ thể của nó quá. Bên cạnh đó, ở trên cung cấp bảo hiểm sifficient cho mã của bạn.

Các vấn đề liên quan