🐈

JUnitのArgumentCaptorとVerifyの使い方をまとめてみた。

2024/12/19に公開

JUnitのArgumentCaptorとVerifyの使い方をまとめてみた。

はじめに

  • 私はSpringbootの初学者です。
  • JUnitでわからない部分があったので、
    自分の今後のために記事にまとめます。

UserServiceクラスのsendMailメソッドのテストの書き方をまとめてみた。

使用技術

  • SpringBoot
  • Thymeleaf
  • JUnit

ArgumentCaptorとは

  • 渡したい値のクラスを与える。
ArgumentCaptor<キャプチャークラス> captor = ArgumentCaptor.forClass(キャプチャークラス.class);

verifyとは

  • どんな値を与えたか確認する。
verify(モックインスタンス, times(想定回数)).メソッド(引数);

完成したコード

User.java
User.java
public class User {

	//ID
	private Integer id;
	//ユーザー氏名
	private String name;
	//パスワード
	private String password;
	//メールアドレス
	private String email;
	//郵便番号
	private String zipcode;
	//住所
	private String address;
	//電話番号
	private String telephone;

    ~省略~
}
UserService.java
UserService.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.MailSender;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.example.domain.User;
import com.example.repository.UserRepository;
import jakarta.servlet.http.HttpSession;

@Service
@Transactional
public class UserService {
	
	@Autowired
	private HttpSession session;

	@Autowired
	private MailSender sender;

    ~省略~
    	
	/**
	 * 2段階認証のパスワードを入力されたメールアドレスに送信
	 * 
	 * @param email
	 * @param checkPass
	 */
	public void sendMail(String email, String checkPass) {
        SimpleMailMessage msg = new SimpleMailMessage();
        session.setAttribute("checkPass", checkPass);
        session.setAttribute("emailcheck", email);

        msg.setFrom("sample.co.jp");
        msg.setTo(email);
        msg.setSubject("2段階認証パスワード発行"); //タイトルの設定
        msg.setText(checkPass + " こちらを画面に入力してください");  //本文の設定
        this.sender.send(msg);
    }

    ~省略~
UserServiceTest
UserServiceTest.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.MailSender;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.example.domain.User;
import jakarta.servlet.http.HttpSession;

@Service
@Transactional
public class UserService {
	
	@Autowired
	private HttpSession session;
	
	@Autowired
	private MailSender sender;

    ~省略~


	/**
	 * 2段階認証のパスワードを入力されたメールアドレスに送信
	 * 
	 * @param email
	 * @param checkPass
	 */
	public void sendMail(String email, String checkPass) {
        SimpleMailMessage msg = new SimpleMailMessage();
        session.setAttribute("checkPass", checkPass);
        session.setAttribute("emailcheck", email);

        msg.setFrom("sample.co.jp");
        msg.setTo(email);
        msg.setSubject("2段階認証パスワード発行");//タイトルの設定
        msg.setText(checkPass + " こちらを画面に入力してください"); //本文の設定

        this.sender.send(msg);
    }

    ~省略~
}
SimpleMailMessage.java(Springbootで自動生成されます。)
SimpleMailMessage
import java.io.Serializable;
import java.util.Date;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

/**
 * Models a simple mail message, including data such as the from, to, cc, subject,
 * and text fields.
 *
 * <p>Consider {@code JavaMailSender} and JavaMail {@code MimeMessages} for creating
 * more sophisticated messages, for example messages with attachments, special
 * character encodings, or personal names that accompany mail addresses.
 *
 * @author Dmitriy Kopylenko
 * @author Juergen Hoeller
 * @since 10.09.2003
 * @see MailSender
 * @see org.springframework.mail.javamail.JavaMailSender
 * @see org.springframework.mail.javamail.MimeMessagePreparator
 * @see org.springframework.mail.javamail.MimeMessageHelper
 * @see org.springframework.mail.javamail.MimeMailMessage
 */
@SuppressWarnings("serial")
public class SimpleMailMessage implements MailMessage, Serializable {

	@Nullable
	private String from;

	@Nullable
	private String replyTo;

	@Nullable
	private String[] to;

	@Nullable
	private String[] cc;

	@Nullable
	private String[] bcc;

	@Nullable
	private Date sentDate;

	@Nullable
	private String subject;

	@Nullable
	private String text;


	/**
	 * Create a new {@code SimpleMailMessage}.
	 */
	public SimpleMailMessage() {
	}

	/**
	 * Copy constructor for creating a new {@code SimpleMailMessage} from the state
	 * of an existing {@code SimpleMailMessage} instance.
	 */
	public SimpleMailMessage(SimpleMailMessage original) {
		Assert.notNull(original, "'original' message argument must not be null");
		this.from = original.getFrom();
		this.replyTo = original.getReplyTo();
		this.to = copyOrNull(original.getTo());
		this.cc = copyOrNull(original.getCc());
		this.bcc = copyOrNull(original.getBcc());
		this.sentDate = original.getSentDate();
		this.subject = original.getSubject();
		this.text = original.getText();
	}


	@Override
	public void setFrom(@Nullable String from) {
		this.from = from;
	}

	@Nullable
	public String getFrom() {
		return this.from;
	}

	@Override
	public void setReplyTo(@Nullable String replyTo) {
		this.replyTo = replyTo;
	}

	@Nullable
	public String getReplyTo() {
		return this.replyTo;
	}

	@Override
	public void setTo(@Nullable String to) {
		this.to = new String[] {to};
	}

	@Override
	public void setTo(String... to) {
		this.to = to;
	}

	@Nullable
	public String[] getTo() {
		return this.to;
	}

	@Override
	public void setCc(@Nullable String cc) {
		this.cc = new String[] {cc};
	}

	@Override
	public void setCc(@Nullable String... cc) {
		this.cc = cc;
	}

	@Nullable
	public String[] getCc() {
		return this.cc;
	}

	@Override
	public void setBcc(@Nullable String bcc) {
		this.bcc = new String[] {bcc};
	}

	@Override
	public void setBcc(@Nullable String... bcc) {
		this.bcc = bcc;
	}

	@Nullable
	public String[] getBcc() {
		return this.bcc;
	}

	@Override
	public void setSentDate(@Nullable Date sentDate) {
		this.sentDate = sentDate;
	}

	@Nullable
	public Date getSentDate() {
		return this.sentDate;
	}

	@Override
	public void setSubject(@Nullable String subject) {
		this.subject = subject;
	}

	@Nullable
	public String getSubject() {
		return this.subject;
	}

	@Override
	public void setText(@Nullable String text) {
		this.text = text;
	}

	@Nullable
	public String getText() {
		return this.text;
	}


	/**
	 * Copy the contents of this message to the given target message.
	 * @param target the {@code MailMessage} to copy to
	 */
	public void copyTo(MailMessage target) {
		Assert.notNull(target, "'target' MailMessage must not be null");
		if (getFrom() != null) {
			target.setFrom(getFrom());
		}
		if (getReplyTo() != null) {
			target.setReplyTo(getReplyTo());
		}
		if (getTo() != null) {
			target.setTo(copy(getTo()));
		}
		if (getCc() != null) {
			target.setCc(copy(getCc()));
		}
		if (getBcc() != null) {
			target.setBcc(copy(getBcc()));
		}
		if (getSentDate() != null) {
			target.setSentDate(getSentDate());
		}
		if (getSubject() != null) {
			target.setSubject(getSubject());
		}
		if (getText() != null) {
			target.setText(getText());
		}
	}


	@Override
	public boolean equals(@Nullable Object other) {
		return (this == other || (other instanceof SimpleMailMessage that &&
				ObjectUtils.nullSafeEquals(this.from, that.from) &&
				ObjectUtils.nullSafeEquals(this.replyTo, that.replyTo) &&
				ObjectUtils.nullSafeEquals(this.to, that.to) &&
				ObjectUtils.nullSafeEquals(this.cc, that.cc) &&
				ObjectUtils.nullSafeEquals(this.bcc, that.bcc) &&
				ObjectUtils.nullSafeEquals(this.sentDate, that.sentDate) &&
				ObjectUtils.nullSafeEquals(this.subject, that.subject) &&
				ObjectUtils.nullSafeEquals(this.text, that.text)));
	}

	@Override
	public int hashCode() {
		return ObjectUtils.nullSafeHash(this.from, this.replyTo, this.to, this.cc,
				this.bcc, this.sentDate, this.subject);
	}

	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder("SimpleMailMessage: ");
		sb.append("from=").append(this.from).append("; ");
		sb.append("replyTo=").append(this.replyTo).append("; ");
		sb.append("to=").append(StringUtils.arrayToCommaDelimitedString(this.to)).append("; ");
		sb.append("cc=").append(StringUtils.arrayToCommaDelimitedString(this.cc)).append("; ");
		sb.append("bcc=").append(StringUtils.arrayToCommaDelimitedString(this.bcc)).append("; ");
		sb.append("sentDate=").append(this.sentDate).append("; ");
		sb.append("subject=").append(this.subject).append("; ");
		sb.append("text=").append(this.text);
		return sb.toString();
	}


	@Nullable
	private static String[] copyOrNull(@Nullable String[] state) {
		if (state == null) {
			return null;
		}
		return copy(state);
	}

	private static String[] copy(String[] state) {
		return state.clone();
	}

}

解説

  • @InjectMocksで対象となるクラスを指定します。
  • ArgumentCaptorSimpleMailMessageの引数が期待通りか確認します。
  • verifyでモックのメソッド(send, setAttributeなど)が正しく呼ばれているか確認します。
  • 今回のsendMailメソッドで、
    セッションにemailcheckcheckPassが正しく設定されているか、
    MailSenderが正しい宛先、件名、本文で送信できているかを確認しています。

最後に

  • 自分のメモ感覚でまとめまし。
  • もし、不備等あればコメント等で教えていただけると幸いです。

参考文献

https://zenn.dev/kenta123/articles/23d9496738c0d8
https://qiita.com/kyabetsuda/items/16c565460580a8354f6a

Discussion