【问题标题】:Spock and Groovy: variable assignment results in nullSpock 和 Groovy:变量赋值导致 null
【发布时间】:2020-03-04 06:52:03
【问题描述】:

我在 Spock 中的测试有问题:

@Subject
def mutation = new OrderedServicesMutation(long list of constructor elements here)

def "should order service and create address"() {
    given:
    def command = new OrderServiceCommand(1L, 2L, new Date(), "SomeAddress")
    def user = new User(id: command.userId)
    def address = new String()
    def service = new Service(id: command.serviceId)
    and:
    userRepository.findById(command.userId) >> Optional.of(user)
    serviceRepository.findById(command.serviceId) >> Optional.of(service)

    when:
    def result = mutation.orderService(command)

    then:
    with(result) {
        user == user
        address == address
        service == service
    }
}

OrderedServicesMutation.java:

@Component
@AllArgsConstructor
public class OrderedServicesMutation implements GraphQLMutationResolver {

// imports removed for readibility

    @Transactional
@PreAuthorize("hasAnyAuthority('ACCOUNT_OWNER','USER')")
public OrderedService orderService(OrderServiceCommand command) {
    OrderedService orderedService = orderedServiceRepository.save(
            orderedServiceMapper.mapWithHistory(
                    userRepository.findById(command.getUserId()).orElseThrow(() -> new NotFoundException(User.class)),
                    command.getAddress(),
                    serviceRepository.findById(command.getServiceId()).orElseThrow(() -> new NotFoundException(Service.class)),
                    command.getDate()
            )
    );
    orderedServicePublisher.publish(orderedService);

    return orderedService;
}

该方法应该返回一个OrderedService类型的对象,它通常是在运行时,但是当我运行这个测试时,我得到:

Target of 'with' block must not be null

调试测试显示result 变量为空...

为什么 Spock 没有将 mutation.orderService(command) 的结果赋值给 result 变量?

【问题讨论】:

  • 我认为你应该发布一个orderService 方法实现。没有代码,实际上很难说什么。
  • 我已经添加了代码。
  • 使用user==user 之类的东西看起来非常奇怪,我希望这始终是正确的
  • @dziki 什么是orderedServiceMapper 对象和mapWithHistory 方法?我在你的测试中看不到它们。我还假设实现中的orderedServiceRepository 是您的测试中的serviceRepository,对吗?
  • 好的,刚刚发现serviceRepository不是orderedServiceRepository。通常,您的方法将返回与orderedServiceRepository.save 相同的对象。似乎它没有被嘲笑所以它返回null。我说的对吗?

标签: java unit-testing groovy junit spock


【解决方案1】:

您可以模拟 Repository.save 的答案,让它返回在测试执行期间收到的任何内容:

and:
1 * orderedServiceRepository.save(_) >> { args -> args[0] }

在大多数情况下,声明接收任何东西(_) 并不是一个好习惯。至少,您可以像这样指定参数的类型:(_ as OrderedService)

Groovier 也可以使用闭包:

result.with {
  assert it.user == user
  assert it.address == address
  assert it.service == service
}

我认为你需要闭包内的断言,不确定何时像你一样将它用作函数。

添加基数也是一个很好的做法,这样您就可以知道模拟被调用了多少次。

到最后,您还可以确保不再对任何已声明的模拟进行交互,这对于确保没有任何意外交互非常有用:

and: 'No more interactions'
0 * _

这就是我编写此规范的方式:

def "should order service and create address"() {
    given:
    def command = new OrderServiceCommand(1L, 2L, new Date(), "SomeAddress")
    def user = new User(id: command.userId)
    def address = new String()
    def service = new Service(id: command.serviceId)

    when:
    def result = mutation.orderService(command)

    then:
    1 * userRepository.findById(command.userId) >> Optional.of(user)

    and: 
    1 * serviceRepository.findById(command.serviceId) >> Optional.of(service)

    and:
    1 * orderedServiceRepository.save(_ as OrderedService) >> { args -> args[0] }

    and: 'Make sure Publisher receives correct OrderedService' // if you wish to do so
    1 * orderedServicePublisher.publish(_) >> { OrderedService arg ->
      assert arg.user == user
      assert arg.address == address
      assert arg.service == service
    }

    and: // don't really see why use with closure here
    result.user == user
    result.address == address
    result.service == service

    and: 'No more interactions'
    0 * _
}

【讨论】:

  • 我还有其他改进,但它们可能超出了这里的范围。我希望这会有所帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-12
  • 2021-03-10
  • 1970-01-01
  • 2018-10-11
  • 2011-02-28
相关资源
最近更新 更多