これまでのところ、SOからの回答は私の問題を完全に満足させていました。私はJunitとMockitoの単体テストを学んでおり、Spring Webアプリケーションの一部であるサービスクラスをテストしたいと思います。私は多くのチュートリアルや記事を読んでいますが、私はまだ自分のサービス層に適切な単体テストを書く上で問題があります。私は私の質問のための答えを知りたいのですが、最初、私はいくつかのコードを貼り付けます。mockitoを使用したSpringサービスユニットのテスト
Serviceクラス
public class AccountServiceImpl implements AccountService {
@Autowired
AccountDao accountDao, RoleDao roleDao, PasswordEncoder passwordEncoder, SaltSource saltSource;
@PersistenceContext
EntityManager entityManager;
public Boolean registerNewAccount(Account newAccount) {
entityManager.persist(newAccount);
newAccount.setPassword(passwordEncoder.encodePassword(newAccount.getPassword(), saltSource.getSalt(newAccount)));
setRoleToAccount("ROLE_REGISTERED", newAccount);
return checkIfUsernameExists(newAccount.getUsername());
}
public void setRoleToAccount(String roleName, Account account) {
List<Role> roles = new ArrayList<Role>();
try {
roles.add(roleDao.findRole(roleName));
} catch(RoleNotFoundException rnf) {
logger.error(rnf.getMessage());
}
account.setRoles(roles);
}
public Boolean checkIfUsernameExists(String username) {
try {
loadUserByUsername(username);
} catch(UsernameNotFoundException unf) {
return false;
}
return true;
}
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
try {
Account loadedAccount = accountDao.findUsername(username);
return loadedAccount;
} catch (UserNotFoundException e) {
throw new UsernameNotFoundException("User: " + username + "not found!");
}
}
}
私の未完成のテストクラス
@RunWith(MockitoJUnitRunner.class)
public class AccountServiceImplTest {
private AccountServiceImpl accountServiceImpl;
@Mock private Account newAccount;
@Mock private PasswordEncoder passwordEncoder;
@Mock private SaltSource saltSource;
@Mock private EntityManager entityManager;
@Mock private AccountDao accountDao;
@Mock private RoleDao roleDao;
@Before
public void init() {
MockitoAnnotations.initMocks(this);
accountServiceImpl = new AccountServiceImpl();
ReflectionTestUtils.setField(accountServiceImpl, "entityManager", entityManager);
ReflectionTestUtils.setField(accountServiceImpl, "passwordEncoder", passwordEncoder);
ReflectionTestUtils.setField(accountServiceImpl, "saltSource", saltSource);
ReflectionTestUtils.setField(accountServiceImpl, "accountDao", accountDao);
ReflectionTestUtils.setField(accountServiceImpl, "roleDao", roleDao);
}
@Test
public void testRegisterNewAccount() {
Boolean isAccountCreatedSuccessfully = accountServiceImpl.registerNewAccount(newAccount);
verify(entityManager).persist(newAccount);
verify(newAccount).setPassword(passwordEncoder.encodePassword(newAccount.getPassword(), saltSource.getSalt(newAccount)));
assertTrue(isAccountCreatedSuccessfully);
}
@Test
public void testShouldSetRoleToAccount() throws RoleNotFoundException{
Role role = new Role(); //Maybe I can use mock here?
role.setName("ROLE_REGISTERED");
when(roleDao.findRole("ROLE_REGISTERED")).thenReturn(role);
accountServiceImpl.setRoleToAccount("ROLE_REGISTERED", newAccount);
assertTrue(newAccount.getRoles().contains(role));
}
}
質問を :
- 私のサービスクラスのようなメソッドでメソッドがある場合に単体テストを行う最良の方法は何ですか?上記のように個別にテストすることはできますか? [私のコードをいくつかのメソッドに分割して、よりクリーンなコードにする]
- 私のサービスメソッドのための良いユニットテストですか?テストは緑ですが、私はそれについてはわかりません。
- 私はtestShouldSetRoleToAccountに失敗しています。私は間違って何をしていますか?
- checkIfUsernameExistsをテストするにはどうすればよいですか?
私は数日を過ごし、私は進歩をしなかったので、多分誰かがこれで私を助ける:(
UPDATE
完成テストクラス
@RunWith(MockitoJUnitRunner.class)
public class AccountServiceImplTest extends BaseTest {
private AccountServiceImpl accountServiceImpl;
private Role role;
private Account account;
@Mock private Account newAccount;
@Mock private PasswordEncoder passwordEncoder;
@Mock private SaltSource saltSource;
@Mock private EntityManager entityManager;
@Mock private AccountDao accountDao;
@Mock private RoleDao roleDao;
@Before
public void init() {
accountServiceImpl = new AccountServiceImpl();
role = new Role();
account = new Account();
ReflectionTestUtils.setField(accountServiceImpl, "entityManager", entityManager);
ReflectionTestUtils.setField(accountServiceImpl, "passwordEncoder", passwordEncoder);
ReflectionTestUtils.setField(accountServiceImpl, "saltSource", saltSource);
ReflectionTestUtils.setField(accountServiceImpl, "accountDao", accountDao);
ReflectionTestUtils.setField(accountServiceImpl, "roleDao", roleDao);
}
@Test
public void testShouldRegisterNewAccount() {
Boolean isAccountCreatedSuccessfully = accountServiceImpl.registerNewAccount(newAccount);
verify(entityManager).persist(newAccount);
verify(newAccount).setPassword(passwordEncoder.encodePassword(newAccount.getPassword(), saltSource.getSalt(newAccount)));
assertTrue(isAccountCreatedSuccessfully);
}
@Test(expected = IllegalArgumentException.class)
public void testShouldNotRegisterNewAccount() {
doThrow(new IllegalArgumentException()).when(entityManager).persist(account);
accountServiceImpl.registerNewAccount(account);
}
@Test
public void testShouldSetRoleToAccount() throws RoleNotFoundException {
when(roleDao.findRole(anyString())).thenReturn(role);
accountServiceImpl.setRoleToAccount("ROLE_REGISTERED", account);
assertTrue(account.getRoles().contains(role));
}
@Test
public void testShouldNotSetRoleToAccount() throws RoleNotFoundException {
when(roleDao.findRole(anyString())).thenThrow(new RoleNotFoundException());
accountServiceImpl.setRoleToAccount("ROLE_RANDOM", account);
assertFalse(account.getRoles().contains(role));
}
@Test
public void testCheckIfUsernameExistsIsTrue() throws UserNotFoundException {
when(accountDao.findUsername(anyString())).thenReturn(account);
Boolean userExists = accountServiceImpl.checkIfUsernameExists(anyString());
assertTrue(userExists);
}
@Test
public void testCheckIfUsernameExistsIsFalse() throws UserNotFoundException {
when(accountDao.findUsername(anyString())).thenThrow(new UserNotFoundException());
Boolean userExists = accountServiceImpl.checkIfUsernameExists(anyString());
assertFalse(userExists);
}
@Test
public void testShouldLoadUserByUsername() throws UserNotFoundException {
when(accountDao.findUsername(anyString())).thenReturn(account);
Account foundAccount = (Account) accountServiceImpl.loadUserByUsername(anyString());
assertEquals(account, foundAccount);
}
@Test(expected = UsernameNotFoundException.class)
public void testShouldNotLoadUserByUsername() throws UserNotFoundException {
when(accountDao.findUsername(anyString())).thenThrow(new UsernameNotFoundException(null));
accountServiceImpl.loadUserByUsername(anyString());
}
}
Davidありがとうございます。質問1に返信私は完全に理解しており、私はオプション1を選択しました。質問3について私は問題を解決することができました。私は、新しいオペレータによって作成されたアカウントと模擬アカウントを置き換えなければなりませんでした。それは[sic!] :)でした。質問4も私を助けましたが、私には他の問題があります。あなたのヒントのおかげで、私はすべての方法のテストを書くことができました。彼らは、testShouldNotSetRoleToAccountとtestShouldNotLoadUserByUsernameを除いてOKです。 "expected = ..."があると両方が失敗します。それなしでOK。さらに、最初にenエラーを作成し、テストは Errorです。私たちを手伝ってくれますか? –
申し訳ありませんが、私はあなたに戻って取得するためにしばらく時間がかかりました。これらのテストが期待される例外セットで失敗した場合、例外が実際にスローされないことを意味します。 'roleDao'と' accountDao'が実際にモックに設定されていますか?これはデバッガで確認できます。また、あなたは 'anyString()'を正しく使用していません - これはスタブと検証のためのもので、実際にメソッドを実行しているわけではありません。これがあなたの問題の原因かどうかはわかりません。実際にあなたのメソッドを実行する行では、 'anyString()'の代わりに渡す実際の値を入れてください。 –
ええ、私はばかです。私が話していたこのエラーは、ロガーのコンソール情報でした。例外が捕捉されたときのroleDaoにはlogger.error(..):Pがあります。私は徹底的にテストコードを見て、今はすべてOKです。 testShouldNotSetRoleToAccountの "expected"とtestCheckIfUsernameExistsIsFalseは必要ありません。後でテストクラスを更新し、このディスカッションを閉じることができます。もう一度Davidに感謝します。あなたのヒントはとても役に立ちました:) –