当前位置: 首页 > 知识库问答 >
问题:

如何在Grails单元测试中使用Spock模拟passwordEncoder

隗翰海
2023-03-14

在如何模拟Grails单元测试中使用的自动有线依赖方面,我可以提供一些建议。我省略了大部分不必要的代码,只给出了测试类和被测试文件类中的相关方法

class UserService {

    def springSecurityService // spring bean
    def passwordEncoder // auto wired as per 
    //https://stackoverflow.com/questions/33303585/spring-//security-encode-password-with-       bcrypt-algorithm

.....

    def passwordPreviouslyUsed(String newPassword, def userId){
        def passwordExists = false
        def usersPasswords = findPasswordsForUser(userId)
        usersPasswords.each{ password ->
            if (passwordEncoder.isPasswordValid(oldPassword, newPassword, null)) {
                passwordExists = true
            }
        }
        return passwordExists
    }

    .....
    def findPasswordsForUser(def userId){
        User foundUser = User.findById(userId)
        def passwordsForUser = UserPasswords.createCriteria().list {
            eq('user', foundUser) 
            projections{
                property('password')
            }
        }
        passwordsForUser
    }
class UserServiceSpec extends Specification implements DataTest, ServiceUnitTest<UserService> {

    def passwordEncoder
    def setupSpec() {
        mockDomains User, UserPasswords
    }

    def setup() {
        def stubPasswordEncoder =  Stub(passwordEncoder) {
            isPasswordValid(_, _, _) >> true
         }
         service.passwordEncoder = stubPasswordEncoder
    }


    void "test for user passwordPreviouslyUsed"() {
        given: "a user already exists"
        setup()
        service.createNewUser("testName", "testy@test.com", "Secret1234" )
        //^(does some validation, then User.save())
        User foundUser = User.findByEmail("testy@test.com")
        foundUser.fullName == "testName"
        long testUserId = foundUser.id

        and: "we update the password for that user, and it to the userPasswords"
        UserPasswords newUserPassword = new UserPasswords(
            user: foundUser,
            password: "newPassword1"
        )
        newUserPassword.save()

        //use passwordPreviouslyUsed method to check a string with the same value as the 
        //previously 
        //updated password to check if it has already been used
        when: "we check if the password has been used before"

        def response = service.passwordPreviouslyUsed("newPassword1", fundsyId)

        then:
        response == true
    }

如果不对此依赖性进行攻击或嘲弄,我就会得到错误

Cannot invoke method isPasswordValid() on null object

我尝试存根密码编码器并让它返回true

def stubPasswordEncoder =  Stub(passwordEncoder) {
    isPasswordValid(_, _, _) >> true
 }
 service.passwordEncoder = stubPasswordEncoder

但这会给出一条错误消息:

Stub in 'spock.mock.MockingApi' cannot be applied to         '(java.lang.Object, groovy.lang.Closure)'

有什么方法可以用Spock来嘲笑这种依赖吗?

共有1个答案

赵鸿畴
2023-03-14

Stub和Mock使用一个类--您给它一个实例是空的--因此出现了异常。

您应该可以这样嘲笑它:

def mockPasswordEncoder = Mock(PasswordEncoder) 
// note this is the class 
// org.springframework.security.crypto.password.PasswordEncoder
 类似资料:
  • 我用代码编写了以下旧方法,用于访问服务类中的请求对象,例如:

  • 为了获得可重用和可测试的rxjava代码,我使用ObservableTransformers分离了代码的各个部分。它在生产中工作得很好,但是测试它并不像预期的那么容易,因为我似乎无法模拟那些观察到的ransformers。 when(observableTransformer.apply(any())).thenreturn(observable.just(“mockedtext”)); 一旦调用

  • 我正在尝试使用intellij idea运行单个spock单元测试。 考虑: 在上面的测试中,当我转到测试主体和右上下文菜单时,我得到了两种类型的测试。一个是grails测试,另一个是junit测试。 关于这个问题,公认的答案建议使用jUnit运行程序。但是使用它,代码根本无法编译(可能是因为某些插件和其他类不可用)。 (我不确定,因为这是期望的行为,因为我只是运行一个测试,而不是所有的测试。所以

  • Spock对存根和模拟做了很强的区分。当要更改的内容从被测试类使用的类返回时,请使用存根,这样您就可以测试if语句的另一个分支。使用mock,当您不关心测试中的类返回什么时,只需调用另一个类的另一个方法,并且您希望确保调用了该方法。很整洁。然而,假设您有一个具有流利API的构建器,它使人们。您希望测试调用此生成器的方法。 所以最初,我想只是模拟构建器,然后myMethod()的单元测试应该检查具有

  • 问题内容: 我正在使用RestTemplate 方法发布到端点。在我的测试文件中,我正在测试POST方法。但是用我目前的测试,我得到了POST请求。在测试文件中发出POST请求时,我需要模拟API的帮助 这是我的主文件 这是我的测试文件 问题答案: 您正在测试DataTestRepo类内部的逻辑,因此您不应模拟它。RestTemplate是DataTestRepo内部的一个依赖项,因此这正是您需要

  • 问题内容: 我知道关于模拟和测试有很多问题,但是我发现没有任何问题可以完美地帮助我,因此我仍然对理解以下内容有疑问: 如果我弄错了,请纠正我,但据我所知,单元测试用于隔离测试一个特定类的业务逻辑,并且如果有外部需要的任何对象,它们将被模拟。因此,例如,如果我有一个简单城市居民的管理系统,该系统将居民添加到列表中并按姓名返回居民(假设:居民仅包含一些基本个人信息),如下所示: 如果现在我要进行单元测