gpt4 book ai didi

unit-testing - 如何在Spock单元测试中测试Groovy构造函数并覆盖100%的代码

转载 作者:行者123 更新时间:2023-12-04 04:17:03 47 4
gpt4 key购买 nike

我的问题是:我是Spock测试的新手,并试图在此User Class上获得100%的代码覆盖率。首先,有人可以帮我弄清楚如何测试构造函数。我目前没有使用cobertura插件来覆盖它。另外,如果有人对Spock + Cobertura有所了解,也许您可​​以阐明我做错了什么,以及一些进一步测试的指示。

我有一个代表用户的类:

import java.io.Serializable;
import java.util.Set;

class User implements Serializable {
String email
byte[] photo

static hasMany = [lineups: Lineup]

private static final long serialVersionUID = 1

transient springSecurityService

String username
String password
boolean enabled = true
boolean accountExpired
boolean accountLocked
boolean passwordExpired

User(String username, String password) {
this()
this.username = username
this.password = password
}

@Override
int hashCode() {
username?.hashCode() ?: 0
}

@Override
boolean equals(other) {
is(other) || (other instanceof User && other.username == username)
}


Set<SecRole> getAuthorities() {
SecUserSecRole.findAllBySecUser(this)*.secRole
}

def beforeInsert() {
encodePassword()
}

def beforeUpdate() {
if (isDirty('password')) {
encodePassword()
}
}

protected void encodePassword() {
password = springSecurityService?.passwordEncoder ? springSecurityService.encodePassword(password) : password
}

static transients = ['springSecurityService']

static constraints = {
username blank: false, unique: true
password blank: false

email(unique: true, blank: false, nullable: true) // needs to be moved to account
photo(nullable:true, maxSize: 1024 * 1024 * 2 /* 2MB */)
}

static mapping = {
password column: '`password`'
}

String toString() {
return id + ": " + email + " " + username
}
}

然后,我进行了一个Spock单元测试:(不是我的所有代码都在这里,但仅用于我要求提供信息的示例...
@TestFor(User)
class UserSpec extends Specification {
User user

def setup() {
user = new User(
username: "fredflintstone",
password: "Wilma1",
enabled: true).save(failOnError: true, flush: true)

}

def cleanup() {
user = null
}

// Constructor tests
void "test to check constructor works"() {
when:
mockForConstraintsTests(User, [user])

expect:
user.validate()
user != null
user.username != null
user.password != null
}

void "test #hashCode works"() {
setup:

mockForConstraintsTests(User, [user])

expect:
user.username.hashCode() != null

}

}

最佳答案

第一

您真的不需要(也不应该浪费时间)测试仅在JVM中的某些内容中断时才能中断的代码。测试基本的getter和setter方法不会使您的代码受益,因为逻辑太简单了,难以破解。因此,100%的测试覆盖率是一个糟糕的测试目标。您应该瞄准的是...

  • 可维护的测试
  • 他们可能会走几个月,而无需关注
  • 下一个碰到他们的开发人员不太可能是你
  • 所有测试类的一致性测试格式
  • 花更多的时间来理解测试,更少的时间来“阅读”
  • 一种测试格式,使您可以一目了然地了解测试范围
  • 测试完足够的
  • 后,您不需要外部工具即可告诉您
  • 100%覆盖类的方法(不包括具有琐碎逻辑的方法)
  • 合理完整地覆盖每种方法的输入
  • 每个int参数至少应测试期望值的内部和外部极值,0,负数和正数
  • 理想情况下,如果涉及多个参数,则将测试可能的测试输入的每种组合
  • 实际上,有足够的空间来减少用于测试
  • 的输入量

    这种方法可能会导致代码覆盖工具的眼神有些重叠,但是它将对不断变化的条件做出更好的响应,并使不熟悉的开发人员在尽可能短的时间内加快速度。

    第二

    由于您是Spock的新手,让我们讨论一下。最好的是,对测试进行参数设置非常容易。这是我在单元测试级别上进行测试范围界定的方法(功能测试并不总是那么简单)。您可能会注意到与我上面概述的测试目标有些重叠。
  • 每个类测试1个Spec类(在您的情况下为User.class)
  • 1每方法测试
  • 每个唯一的非空构造函数都被视为方法
  • 1每个可能引发异常的方法的测试
  • 因为异常的测试逻辑通常不能补充正常的测试逻辑
  • 1每个输入组合的测试迭代

  • 这种方法需要对where:阻止有一个健康的了解,但是有很多好处。很容易看到已经测试了哪些方法,很容易看到每种方法已经测试了哪些输入,它极大地鼓励了测试的独立性,它鼓励了代码的重用,辅助方法的重用可以清晰,可预测地分布在多个级别上(单个方法的测试,整个Spec类,多个Spec类),以及我目前无法想到的其他一些内容。

    现在到您的测试用例。如果您的构造函数除了充当巨大的setter方法之外没有做任何其他事情,则不应该在其上花费太多时间。确保没有灾难性事件发生的一个测试案例足够多;我在这里为您提供了有关如何编写Spock测试的示例。我喜欢maps列表方法,因为它使每个测试迭代紧密耦合,并允许可选变量和其他灵活性。如果您想了解更多有关Spock中参数化测试的信息,请参阅 official documentation
    @Unroll(iteration.testName)
    void "testing the constructor"() {
    setup:
    user = new User(
    username: iteration.username,
    password: iteration.password,
    enabled: iteration.enabled).save(failOnError: true, flush: true)
    when:
    mockForConstraintsTests(User, [user])

    expect:
    user != null
    user.validate() == iteration.valid
    user.username == iteration.username
    user.password == iteration.password
    user.enabled == iteration.enabled
    user.username.hashCode() != null // May need modification

    where:
    iteration << [

    [testName: "Testing a normal enabled object"
    username: "fredflintstone"
    password: "Wilma1"
    enabled: true,
    valid: true ],

    [testName: "Testing a normal disabled object"
    username: "fredflintstone"
    password: "Wilma1"
    enabled: false,
    valid: true ],

    [testName: "Testing a disabled user, null name"
    username: null
    password: "Wilma1"
    enabled: false,
    valid: false ],

    [testName: "Testing a disabled user, empty name"
    username: ""
    password: "Wilma1"
    enabled: false,
    valid: false ],
    ]
    }

    如果hashCode()涉及多个参数,则该方法可能应该进行自己的测试,该测试使用Stub来仅设置测试该方法所需的User.class部分。

    个人意见警告!
    尽管Coverage插件很有趣,但它们分散了人们的注意力并掩盖了典型jUnit方法进行单元测试所固有的一些重大缺陷。

    如果您有100个测试,每种方法可能对每个输入排列进行一次测试,那么100%的代码覆盖率得分是否重要?有点。您有某种程度的证据证明所有内容均已覆盖,但您可能无法将该覆盖范围追溯到任何单个测试。如果您没有足够的能力立即使用它,则会给您带来一些小的理解。代码覆盖率工具还不错。像我上面概述的那样,一种好的测试范围界定方法可以帮助您从测试指标中获得更多的实用性。他们很容易成为不良测试方法的拐杖。

    关于unit-testing - 如何在Spock单元测试中测试Groovy构造函数并覆盖100%的代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32402084/

    47 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com