自动测试时除了检查加入新资料,有时我们也会希望检查旧资料是否成功地被移除。
今天我们用一个新的功能,来展示如何针对不应该存在的资料进行检查。
我们多加一个新的函数,可以接收 listOf(tag)
,来更新 user
所有的 tag
重点是,我们这边更新的内容,不仅仅是针对单一个 user
我们还接受传 listOf(user)
,一次更新所有的 user.tags
fun updateUsersTags(users: List<User>, tags: List<Tag>) {
}
像昨天一样,我们在 tests/kotlin/
资料夹内,建立 UpdateUsersTagsKtTest.kt
档案,并加上几个测试案例
internal class UpdateUsersTagsKtTest {
fun `测试单一全新用户加上标签`() {
Database.connect("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;", driver = "org.h2.Driver")
transaction {
SchemaUtils.create(Users)
SchemaUtils.create(Tags)
SchemaUtils.create(UsersTags)
val testUser = User.new {
name = "TestUser"
}
val testTag = Tag.new {
name = "TestTag"
}
updateUsersTags(listOf(testUser), listOf(testTag))
assertEquals(
listOf(testTag),
testUser.tags.toList()
)
}
}
}
运作测试看看,我们发现测试并没有通过
expected:<[Tag@2380d06e]> but was:<[]>
Expected :[Tag@2380d06e]
Actual :[]
这是理所当然的,因为我们的 updateUsersTags()
里面还是空的
我们根据昨天的 userAddTag()
稍微调整一下写法,看看能不能通过
fun updateUsersTags(users: List<User>, tags: List<Tag>) {
transaction {
users.forEach {
it.tags = SizedCollection(it.tags.toList() + tags)
}
}
}
重新运作测试,就可以通过了。
我们多加另一个测试的案例 测试多个用户加上标签
@Test
fun `测试多个用户加上标签`() {
Database.connect(
"jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;",
driver = "org.h2.Driver"
)
transaction {
SchemaUtils.create(Users)
SchemaUtils.create(Tags)
SchemaUtils.create(UsersTags)
val testUser = User.new {
name = "TestUser"
}
val testUser2 = User.new {
name = "TestUse2"
}
val testTag = Tag.new {
name = "TestTag"
}
updateUsersTags(listOf(testUser, testUser2), listOf(testTag))
assertEquals(listOf(testTag), testUser.tags.toList())
assertEquals(listOf(testTag), testUser2.tags.toList())}
}
这个测试也可以成功通过
为求测试的完整,我们再加上 测试已有标签用户更动新标签
@Test
fun `测试已有标签用户更动新标签`() {
Database.connect(
"jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;",
driver = "org.h2.Driver"
)
transaction {
SchemaUtils.create(Users)
SchemaUtils.create(Tags)
SchemaUtils.create(UsersTags)
val testUser = User.new {
name = "TestUser"
}
val testTag = Tag.new {
name = "TestTag"
}
val testTag2 = Tag.new {
name = "TestTag2"
}
testUser.tags = SizedCollection(listOf(testTag))
updateUsersTags(listOf(testUser), listOf(testTag2))
assertEquals(listOf(testTag2), testUser.tags.toList())
}
}
执行之後,我们发现以下错误
expected:<[Tag@641aca5a]> but was:<[Tag@60c77761, Tag@641aca5a]>
Expected :[Tag@641aca5a]
Actual :[Tag@60c77761, Tag@641aca5a]
这是怎麽回事呢?不是只是拿昨天的程序做了一点调整吗?
和我们的需求逻辑比较之後,我们会发现,这是因为昨天的逻辑是「新增」,但是今天需求的逻辑是「更新」导致的。
我们需要再调整一下我们的程序
fun updateUsersTags(users: List<User>, tags: List<Tag>) {
transaction {
users.forEach {
it.tags = SizedCollection(tags)
}
}
}
这样的话,我们的 测试已有标签用户更动新标签
就会通过了。
我们可以再增加一些测试案例,像是
测试多个已有标签用户更动新标签
测试多个已有标签用户更动多个新标签
@Test
fun `测试多个已有标签用户更动新标签`() {
Database.connect(
"jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;",
driver = "org.h2.Driver"
)
transaction {
SchemaUtils.create(Users)
SchemaUtils.create(Tags)
SchemaUtils.create(UsersTags)
val testUser = User.new {
name = "TestUser"
}
val testUser2 = User.new {
name = "TestUser2"
}
val testTag = Tag.new {
name = "TestTag"
}
val testTag2 = Tag.new {
name = "TestTag2"
}
testUser.tags = SizedCollection(listOf(testTag))
testUser2.tags = SizedCollection(listOf(testTag))
updateUsersTags(listOf(testUser, testUser2), listOf(testTag2))
assertEquals(listOf(testTag2), testUser.tags.toList())
assertEquals(listOf(testTag2), testUser2.tags.toList())
}
}
@Test
fun `测试多个已有标签用户更动多个新标签`() {
Database.connect(
"jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;",
driver = "org.h2.Driver"
)
transaction {
SchemaUtils.create(Users)
SchemaUtils.create(Tags)
SchemaUtils.create(UsersTags)
val testUser = User.new {
name = "TestUser"
}
val testUser2 = User.new {
name = "TestUser2"
}
val oldTag = Tag.new {
name = "oldTag"
}
val testTag = Tag.new {
name = "TestTag"
}
val testTag2 = Tag.new {
name = "TestTag2"
}
testUser.tags = SizedCollection(listOf(oldTag))
testUser2.tags = SizedCollection(listOf(oldTag))
updateUsersTags(listOf(testUser, testUser2), listOf(testTag, testTag2))
assertEquals(listOf(testTag, testTag2), testUser.tags.toList())
assertEquals(listOf(testTag, testTag2), testUser2.tags.toList())
}
}
这些测试都可以顺利通过,代表我们的程序应该是没有问题的。
不过,虽然程序本身没有问题,但是刚刚「更新」和「新增」之间的逻辑区分,确实让我们花了点时间确认,未来的工程师可能在这里也会遇到类似的逻辑问题。
如果我们想要强调这段程序是「更新」而不是「新增」,自动测试也能帮助我们吗?
上面的问题,答案是:可以的!
我们可以加上一个案例 测试更新已有标签用户时应移除旧标签
。这样一来,如果有人不小心将这段程序,改成没有移除旧标签的版本,他就会从错误讯息内,看到这个未通过的测试案例,进而提醒他应该要移除掉旧标签。
测试更新已有标签用户时应移除旧标签
这个测试案例,要强调「应移除旧标签」,所以用之前的 assertEquals()
断言是不够的。
这边我们要利用 org.junit.Assert.*
套件的 assertThat()
,搭配上 org.hamcrest.CoreMatchers.*
套件的 not()
和 hasItem()
,来协助我们断言旧标签不存在於更新之後的 user.tags
内
我们来实作一下 测试更新已有标签用户时应移除旧标签
fun `测试更新已有标签用户时应移除旧标签`() {
Database.connect(
"jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;",
driver = "org.h2.Driver"
)
transaction {
SchemaUtils.create(Users)
SchemaUtils.create(Tags)
SchemaUtils.create(UsersTags)
val testUser = User.new {
name = "TestUser"
}
val oldTag = Tag.new {
name = "oldTag"
}
val newTag = Tag.new {
name = "newTag"
}
testUser.tags = SizedCollection(listOf(oldTag))
updateUsersTags(listOf(testUser), listOf(newTag))
assertThat(testUser.tags.toList(), not(hasItem(oldTag)))
}
这个测试案例运行通过之後,可以保证之後的修改,如果不小心在执行 updateUsersTags()
时,没有移除旧标签的话,可以在自动测试的阶段就被发现到。
<<: 06 - TPM - Tmux Plugin Manager 与它的插件
是我们今天要聊的内容,老样的,如果你已经可以轻松看懂,欢迎直接左转去看同事 Ken 精彩的文章 —...
在Microsoft Defender for Endpoint中有提供自动化调查和补救功能。 自动...
在UI出图之前,我们先确认好目前的 wireframe 是完整的。接下来只要依照 wireframe...
Event Handling 在开发元件时一定少不了会需要触发事件的时候,像是 click 事件、i...
字典特徵 字典和阵列类似,也是可变序列,但它是无序的,保存的内容是以「键:值」的形式存放的。 键是唯...