0

I have a test:

def "should get product by id"() {
        given:
        Product product = getBeer(UPLOADED_FILE_DETAILS_IMG)
        productRepository.getByIdOrThrow(product.id().get()) >> product

        then:
        productRepository.getByIdOrThrow(_) >> { Product found ->
            found.name() == product.name()
            found.description() == product.description()
            found.category() == product.category()
            found.price() == product.price()
            found.creationDate() == product.creationDate()
        }
    }

That tests this method:

public Product getProductById(Long productId) {
        return productRepository.getByIdOrThrow(productId);
}

And I get this error:

groovy.lang.MissingMethodException: No signature of method: pl.itcraft.domain.products.ProductApplicationServiceIT$__spock_feature_1_2_closure3.doCall() is applicable for argument types: (ArrayList) values: [[1]]
Possible solutions: doCall(pl.itcraft.domain.products.Product), findAll(), findAll(), isCase(java.lang.Object), isCase(java.lang.Object)

    at groovy.lang.Closure.call(Closure.java:412)
    at org.spockframework.mock.response.CodeResponseGenerator.invokeClosure(CodeResponseGenerator.java:54)
    at org.spockframework.mock.response.CodeResponseGenerator.doRespond(CodeResponseGenerator.java:37)
    at org.spockframework.mock.response.SingleResponseGenerator.respond(SingleResponseGenerator.java:32)
    at org.spockframework.mock.response.ResponseGeneratorChain.respond(ResponseGeneratorChain.java:44)
    at org.spockframework.mock.runtime.MockInteraction.accept(MockInteraction.java:73)
    at org.spockframework.mock.runtime.MockInteractionDecorator.accept(MockInteractionDecorator.java:50)
    at org.spockframework.mock.runtime.InteractionScope$1.accept(InteractionScope.java:57)
    at org.spockframework.mock.runtime.MockController.handle(MockController.java:40)
    at org.spockframework.mock.runtime.JavaMockInterceptor.intercept(JavaMockInterceptor.java:92)
    at org.spockframework.mock.runtime.DynamicProxyMockInterceptorAdapter.invoke(DynamicProxyMockInterceptorAdapter.java:34)
    at org.spockframework.spring.mock.DelegatingInterceptor.intercept(DelegatingInterceptor.java:53)
    at org.spockframework.mock.runtime.DynamicProxyMockInterceptorAdapter.invoke(DynamicProxyMockInterceptorAdapter.java:34)
    at pl.itcraft.domain.products.ProductApplicationService.getProductById(ProductApplicationService.java:38)
    at pl.itcraft.domain.products.ProductApplicationServiceIT.should get product by id(ProductApplicationServiceIT.groovy:64)

It doesn't make any sense to me, I am not providing any array here. Can you see what might be wrong with this test?

  • You test shouldn't even compile, a `then`-block always requires a preceding `when`-block. Furthermore, you need to [combine stubbing and mocking](https://spockframework.org/spock/docs/2.0/all_in_one.html#_combining_mocking_and_stubbing) into one. – Leonard Brünings Sep 09 '21 at 09:30
  • I would appreciate feedback to my answer. Thank you. This question is still listed as open, even though Leonard and I have solved your problem a while ago already. – kriegaex Oct 20 '21 at 08:37

1 Answers1

2

In order to illustrate Leonard's statement, I created an MCVE on your behalf. Next time, please prepare one by yourself, because that is your job when asking questions here. I had to guess and create some dummy classes in order to create something resembling your own test:

package de.scrum_master.stackoverflow.q69086117;

import java.util.Date;

public class Product {
  private long _id;
  private String _name;
  private String _description;
  private String _category;
  private long _price;
  private Date _creationDate;

  public Product(long id, String name, String description, String category, long price, Date creationDate) {
    this._id = id;
    this._name = name;
    this._description = description;
    this._category = category;
    this._price = price;
    this._creationDate = creationDate;
  }

  @Override
  public String toString() {
    return "Product{" +
           "id=" + _id +
           ", name='" + _name + '\'' +
           ", description='" + _description + '\'' +
           ", category='" + _category + '\'' +
           ", price=" + _price +
           ", creationDate=" + _creationDate +
           '}';
  }

  @Override
  public boolean equals(Object o) {
    if (this == o)
      return true;
    if (o == null || getClass() != o.getClass())
      return false;

    Product product = (Product) o;

    return _id == product._id;
  }

  @Override
  public int hashCode() {
    return (int) (_id ^ (_id >>> 32));
  }

  public long id() {
    return _id;
  }

  public String name() {
    return _name;
  }

  public String description() {
    return _description;
  }

  public String category() {
    return _category;
  }

  public long price() {
    return _price;
  }

  public Date creationDate() {
    return _creationDate;
  }
}
package de.scrum_master.stackoverflow.q69086117;

import java.util.HashSet;
import java.util.Optional;
import java.util.Set;

public class ProductRepository {
  private static ProductRepository productRepository;
  private Set<Product> products = new HashSet<>();

  public static void setProductRepository(ProductRepository productRepository) {
    ProductRepository.productRepository = productRepository;
  }

  public boolean add(Product product) {return products.add(product);}

  public boolean remove(Object o) {return products.remove(o);}

  public Product getProductById(Long productId) {
    return productRepository.getByIdOrThrow(productId);
  }

  private Product getByIdOrThrow(Long productId) {
    Optional<Product> productOptional = products.stream().filter(product -> product.id() == productId).findAny();
    if (!productOptional.isPresent())
      throw new RuntimeException("Product with ID " + productId + " not found");
    return productOptional.get();
  }
}
package de.scrum_master.stackoverflow.q69086117

import spock.lang.Specification

class ProductTest extends Specification {
  static def UPLOADED_FILE_DETAILS_IMG = "dummy"

  def "should get product by id"() {
    given:
    Product product = getBeer(UPLOADED_FILE_DETAILS_IMG)
    ProductRepository productRepository = Mock() {
      getProductById(product.id()) >> product
    }

    when:
    def found = productRepository.getProductById(product.id())

    then:
    found.name() == product.name()
    found.description() == product.description()
    found.category() == product.category()
    found.price() == product.price()
    found.creationDate() == product.creationDate()
  }

  Product getBeer(Object o) {
    def endOf20thCentury = new GregorianCalendar()
    endOf20thCentury.set(1999, 12 - 1, 31, 23, 59, 59)
    new Product(11, "Beer", "A popular alcoholic drink", "Beverages", 123, endOf20thCentury.toLocalDateTime().toDate())
  }
}

Of course, this test does not make much sense, because we are directly testing the mock instead of injecting the mock somewhere and using the mock as a tool in order to test another class. But I think that at least you understand the principle.

kriegaex
  • 63,017
  • 15
  • 111
  • 202