英文:
is making a setter method for only test fine?
问题
以下是您请求的代码部分的中文翻译:
我正在使用Mockito和Junit5进行单元测试。
我根据用户的createdAt字段和今天的日期获取之前的学习记录。所以我想检查我的代码是否获取了学习记录,但问题是createdAt是由JPAAuditing设置的。
@Entity
@EntityListeners(AuditingEntityListener.class)
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true, nullable = false)
private String username;
@Column(unique = true, nullable = false)
private String email;
@Column(nullable = false)
private String password;
@Enumerated(EnumType.STRING)
private UserRole role;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
@CreatedDate
@Column(updatable = false)
private LocalDateTime createdAt;
protected User() {}
protected User(String username, String email, String password) {
this.username = username;
this.email = email;
this.password = password;
this.role = UserRole.USER;
}
public static User of(String username, email, String password, boolean verified) {
return new User(username, email, password, verified);
}
public void setIdForTest(Long id) {
this.id = id;
}
public void setPasswordForTest(String pw) {
this.password = pw;
}
public void setCreatedAtForTest() {
this.createdAt = LocalDateTime.now();
}
public void setCreatedAtForTest(LocalDateTime localDateTime) {
this.createdAt = localDateTime;
}
}
这是获取学习记录的代码:
@Override
public UserDTO.UserDetailWithStudyRecords findPriorStudyRecords(User user) {
LocalDateTime joinDate = user.getCreatedAt();
LocalDateTime date = LocalDateTime.now();
List<String> studiedDates = wordQuerydslRepository.findByUserAndCreatedAtBetweenAndGroupBy(
user,
LocalDateTime.of(joinDate.getYear(), joinDate.getMonth(), 1, 0, 0, 0),
LocalDateTime.of(date.getYear(), date.getMonth(), date.toLocalDate().lengthOfMonth(), 23, 59, 59)
);
// ...
}
我需要操作joinDate。但我想知道是否可以创建一个名为"setCreatedAtForTest"的测试方法。
[测试代码]
@DisplayName("获取学习记录")
@Test
void getStudyRecords() {
User user = UserFixture.getVerifiedUser();
user.setCreatedAtForTest(LocalDateTime.of(2023, 01, 01, 00, 00));
LocalDateTime now = LocalDateTime.now();
List<String> dates = List.of("01/01/2023", "01/02/2023", "02/02/2023", "03/01/2023", "04/01/2023");
given(wordQuerydslRepository.findByUserAndCreatedAtBetweenAndGroupBy(
user,
user.getCreatedAt(),
LocalDateTime.of(now.getYear(), now.getMonth(), now.toLocalDate().lengthOfMonth(), 23, 59, 59))
).willReturn(dates);
}
请注意,代码中的HTML实体已被翻译为相应的字符。
英文:
I'm doing unit test using Mockito and Junit5.
I'm bringing prior study records based on user createdAt field and today date.
So I want to check if my code bring study records but the thing is createdAt is seted up by JPAAuditing.
@Getter
@ToString(callSuper = true)
@Entity
@EntityListeners(AuditingEntityListener.class)
public class User {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@Column(unique = true, nullable = false)
private String username;
@Column(unique = true, nullable = false)
private String email;
@Column(nullable = false)
private String password;
@Enumerated(EnumType.STRING)
private UserRole role;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
@CreatedDate
@Column(updatable = false)
private LocalDateTime createdAt;
protected User() {}
protected User(String username, String email, String password) {
this.username = username;
this.email = email;
this.password = password;
this.role = UserRole.USER;
}
public static User of(String username, String email, String password, boolean verified) {
return new User(username, email, password, verified);
}
public void setIdForTest(Long id) {
this.id = id;
}
public void setPasswordForTest(String pw) {
this.password = pw;
}
public void setCreatedAtForTest() {
this.createdAt = LocalDateTime.now();
}
public void setCreatedAtForTest(LocalDateTime localDateTime) {
this.createdAt = localDateTime;
}
}
This is the code that bringing study records
@Override
public UserDTO.UserDetailWithStudyRecords findPriorStudyRecords(User user) {
LocalDateTime joinDate = user.getCreatedAt();
LocalDateTime date = LocalDateTime.now();
List<String> studiedDates = wordQuerydslRepository.findByUserAndCreatedAtBetweenAndGroupBy(
user,
LocalDateTime.of(joinDate.getYear(), joinDate.getMonth(), 1, 0, 0, 0),
LocalDateTime.of(date.getYear(), date.getMonth(), date.toLocalDate().lengthOfMonth(), 23, 59, 59)
);
...
}
I need to manipulate the joinDate. But im curious if making a test method like "setCreatedAtForTest".
[Test Code]
@DisplayName("공부한 날짜 기록을 가져온다.")
@Test
void getStudyRecords() {
User user = UserFixture.getVerifiedUser();
user.setCreatedAtForTest(LocalDateTime.of(2023, 01, 01, 00, 00));
LocalDateTime now = LocalDateTime.now();
List<String> dates = List.of("01/01/2023", "01/02/2023", "02/02/2023", "03/01/2023", "04/01/2023");
given(wordQuerydslRepository.findByUserAndCreatedAtBetweenAndGroupBy(
user,
user.getCreatedAt(),
LocalDateTime.of(now.getYear(), now.getMonth(), now.toLocalDate().lengthOfMonth(), 23, 59, 59))
).willReturn(dates);
}
答案1
得分: 0
首先,作为一种替代方法,评论中@Carols的建议是正确的:您可以在test/resources
目录中添加一个名为data.sql
的文件,用于初始化数据库并插入一些测试数据。
如果您没有这个替代方法,我会建议创建一个包可见的setter用于测试。或者更好的做法是创建一个包可见的构造函数,该构造函数接收创建日期作为参数。
protected User(String username, String email, String password) {
this(username, email, password);
}
User(String username, String email, String password, LocalDateTime createdDate) {
this.username = username;
this.email = email;
this.password = password;
this.role = UserRole.USER;
this.createdDate = createdDate;
}
这将允许您从测试装置中注入日期来创建用户,或者从与User在同一包中定义的测试生成器中创建用户。即使Uncle Bob在他的一篇文章中指出“测试胜过封装”,但这当然是最后的手段措施:https://blog.cleancoder.com/uncle-bob/2015/07/01/TheLittleSingleton.html
英文:
You have a couple of options for solving this. Firstly, as an alternative, @Carols's suggestion in the comments is correct: you can use add a data.sql
file in your test/resources
directory that initializes the database with some test entries.
If you wouldn't have this alternative, I would say it's ok to create a package-protected setter for tests. Or even better, a packaged-protected constructor that receives the created date.
protected User(String username, String email, String password) {
this(username, email, password);
}
User(String username, String email, String password, LocalDateTime createdDate) {
this.username = username;
this.email = email;
this.password = password;
this.role = UserRole.USER;
this.createdDate = createdDate;
}
This will allow you to create a user injecting that date from the test fixture or from some test builder that is defined in the same package as the User. Even Uncle Bob has an article here he states that "testing trumps encapsulation" - but, of course, this a measure of last resort: https://blog.cleancoder.com/uncle-bob/2015/07/01/TheLittleSingleton.html
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论