I have a service class defined as follows
class MyService {
def otherService;
def performService( ) {
Navigator.navigate( retrieveData, { otherService.doSomething(it) } );
}
def retrieveData = { Integer offset, Integer maxRows
DomainObject.list(offset,maxRows);
}
}
Navigator.navigate( Closure retriever, Closure processor ) {
def offset=0;
def batchsize=100;
while( (data=retriever(offset,batchsize)) ) {
if(data.size()==0) break;
data.each { processor(it) }
offset += data.size();
}
}
In my tests, I would like to mock the retriveData to retrieve mocked objects
#TestFor(MyService)
class MyServiceSpec extends Specification {
def "test retriever"() {
given:
service.otherService = Mock(OtherService);
service.metaClass.retrieveData = { Integer offset, Integer maxRows ->
if(offset==0) return [ Mock(DomainObject), Mock(DomainObject) ]
else return []
}
when:
service.performService();
then:
2 * otherService.doSomething(_);
}
}
It turns out that the test is not picking up the mocked retrieveData, instead it always picks up the MyService.retrieveData closure, wondering what is the right approach to mock a closure method..
Seems that it's because retrieveData is a field, not a method. Can you try:
given:
...
service.retrieveData = { Integer offset, Integer maxRows ->
...
}
Related
I want to use jmockit to test the static method in Spock, and combine the where tag to achieve different values of each mock to test different business logic. I tried a lot of writing methods, but they all failed. I hope I can get help or suggestions here. Thank you very much
Here is an example of my business code:
public class MyUtils {
public static int staticMethod(int origin) {
return 0;
}
}
public class MyClass {
public void verify(int origin) {
if (MyUtils.staticMethod(origin) == 1) {
System.out.println("1");
}
if (MyUtils.staticMethod(origin) == 2) {
System.out.println("2");
}
...
}
}
This is my Spock test code:
def "verify"() {
when:
myClass.verify(0)
then:
true
where:
mock | _
mockStatic(1) | _
mockStatic(2) | _
}
def mockStatic(val){
new MockUp<MyUtils>() {
#Mock
public int staticMethod(int origin) {
return val
}
}
}
I know that power can implement such a function, but because our team has been using jmockit, we want to know whether jmockit can implement such multiple different values of mock in Spock?
Put your method call into a closure and evaluate the closure during each iteration:
package de.scrum_master.stackoverflow.q67882559
import mockit.Mock
import mockit.MockUp
import mockit.internal.state.SavePoint
import spock.lang.Requires
import spock.lang.Specification
import spock.lang.Unroll
class StaticMethodJMockitTest extends Specification {
def jMockitSavePoint = new SavePoint()
def cleanup() {
jMockitSavePoint.rollback()
}
#Unroll
def "verify"() {
given:
mockClosure()
MyClass myClass = new MyClass()
when:
myClass.verify(0)
then:
true
where:
mockClosure << [
{ /* no mock */ },
{ mockStatic(1) },
{ mockStatic(2) }
]
}
def mockStatic(val) {
new MockUp<MyUtils>() {
#Mock
int staticMethod(int origin) {
return val
}
}
}
public static class MyUtils {
public static int staticMethod(int origin) {
return 0;
}
}
public static class MyClass {
public void verify(int origin) {
if (MyUtils.staticMethod(origin) == 1) {
System.out.println("1");
}
if (MyUtils.staticMethod(origin) == 2) {
System.out.println("2");
}
}
}
}
If you wish to use data tables, you need to help the parser a bit by explicitly adding it -> inside in the closure, if the closure is in the first column of the data table. You can also use some nice naming for your unrolled iterations:
#Unroll
def "verify #description"() {
given:
mockClosure()
MyClass myClass = new MyClass()
when:
myClass.verify(0)
then:
true
where:
description | mockClosure
"no mock" | { /* no mock */ }
"mock result 1" | { mockStatic(1) }
"mock result 2" | { mockStatic(2) }
}
The reason for creating and rolling back the save point is that JMockit does not play nice with Spock concerning mock lifecycles and the maintainer has no intention to even think about helping. See JMockit issue #668 for more info.
In my app I use spock in version 2.0-M1-groovy-2.5. I have a problem that even though I mokced a class I get npe from the internals of mocked method.
I have simple class called ReactiveRestHighLevelClient which looks like this
open class ReactiveRestHighLevelClient(val restHighLevelClient: RestHighLevelClient, private val objectMapper: ObjectMapper) {
...
fun index(indexRequest: IndexRequest): Mono<IndexResponse> {
return Mono.create<IndexResponse> { sink ->
restHighLevelClient.indexAsync( // < -- HERE I GET THE NPE EVEN THOUGH THE METHOD IS MOCKED
indexRequest,
object : ActionListener<IndexResponse> {
override fun onFailure(e: Exception) {
e.printStackTrace()
sink.error(e)
}
override fun onResponse(response: IndexResponse) {
sink.success(response)
}
}
)
}
}
...
}
I have class ThreadModelElasticsearchService which uses the ReactiveRestHighLevelClient and looks like this:
#Component
class ThreadModelElasticsearchService(
private val objectMapper: ObjectMapper,
private val reactiveElasticsearchClient: ReactiveRestHighLevelClient,
private val extraFactsService: ExtraFactsService,
private val customerDataService: CustomerDataService,
rateLimiterRegistry: RateLimiterRegistry
) {
...
fun save(operationId: String, threadModel: ThreadModel): Mono<ThreadModel> {
val id = threadModel.threadId
?: ThreadModel.createKey(threadModel.partnerId, threadModel.customerId)
return reactiveElasticsearchClient
.index(
IndexRequest(ThreadModel.INDEX, ThreadModel.TYPE, id)
.source(objectMapper.writeValueAsString(threadModel), XContentType.JSON)
)
.thenReturn(threadModel)
.doOnNext { logger.info("[operation_id=$operationId] -- Saved : $it") }
.onErrorMap { e ->
logger.error("[operation_id=$operationId] -- Error calling elasticSearch", e)
ElasticRepositoryError(e)
}
.rateLimit(elasticRateLimiter)
}
...
}
Finally I have my test class called ThreadModelElasticsearchServiceTest which looks like this:
class ThreadModelElasticsearchServiceTest extends Specification {
ReactiveRestHighLevelClient reactiveElasticsearchClient = Mock()
... other mocks
ThreadModelElasticsearchService threadModelReactiveElasticsearchClient = new
ThreadModelElasticsearchService(objectMapper, reactiveElasticsearchClient, extraFactsService, customerDataService, RateLimiterRegistry.of(RateLimiterConfig.ofDefaults()))
def "should work"() {
given:
ThreadModel threadModel = new ThreadModel(...)
reactiveElasticsearchClient.index(_ as IndexRequest) >> Mono.just(indexResponse)
expect:
threadModelReactiveElasticsearchClient.save("should-work", threadModel).block()
}
When I run the tests I get execption like
java.lang.NullPointerException: null
at com.cb.elastic.search.api.elasticsearch.ReactiveRestHighLevelClient$index$1.accept(ReactiveRestHighLevelClient.kt:76)
which points to the body of the index method of the ReactiveRestHighLevelClient mock which is strange.
How to solve this ?
I have a DSL that includes blocks that need to be wrapped as methods returned inside an anonymous class created by the generated code. For example:
model {
task {
val x = 2*5;
Math.pow(2, x)
}
}
should compile to (note task becoming an instance of Runnable, with the body of the task becoming the body of the Runnable.run() method):
import java.util.Collection;
#SuppressWarnings("all")
public class MyFile {
public Collection<Runnable> tasks() {
ArrayList<Runnable> tasks = new ArrayList<>();
tasks.add(getTask0());
return tasks;
}
public static Runnable getTask0() {
Runnable _runnable = new Runnable() {
public void run() {
final int x = (2 * 5);
Math.pow(2, x);
}
}
return _runnable;
}
}
Following the discussion in this question, I was able to get this particular example to work. (Github repo includes unit tests.) But I had to do it by representing the Task element in the grammar as a sequence of XExpressions (source), which my XbaseCompiler subclass had to iterate over (source).
Instead, it would have been nice to be able to just have Task contain an XBlockExpression in a property action, and then in the compiler just do doInternalToJavaStatement(expr.action, it, isReferenced). My sense is that this is really the "right" solution in my case, but when I tried it, this would result in an empty body of the generated run method, as if the block was not processed at all. What's going on, and am I missing some required bits of setup/wiring things together/bindings that are necessary for this to work?
you ususally try to avoid that by using a better inference strategy e.g.
Grammar
Model:
{Model}"model" "{"
vars+=Variable*
tasks+=Task*
"}"
;
Variable:
"var" name=ID ":" type=JvmParameterizedTypeReference
;
Task:
{Task} "task" content=XBlockExpression
;
Inferrer
class MyDslJvmModelInferrer extends AbstractModelInferrer {
#Inject extension JvmTypesBuilder
def dispatch void infer(Model element, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {
acceptor.accept(element.toClass("test.Model2")) [
for (v : element.vars) {
members+=v.toField(v.name, v.type.cloneWithProxies) [
]
}
var i = 0;
for (t : element.tasks) {
val doRunName = "doRun"+i
members += t.toMethod("task"+i, Runnable.typeRef()) [
body = '''
return new «Runnable» () {
public void run() {
«doRunName»();
}
};
'''
]
members += t.toMethod(doRunName, Void.TYPE.typeRef()) [
body = t.content
]
i = i + 1
}
]
}
}
and that basically is it.
you may follow https://bugs.eclipse.org/bugs/show_bug.cgi?id=481992
If you really want to adapt the xbase typesystem that may be a lot more of work e.g. (just covering a minimal case)
Grammar
Model:
{Model}"model" "{"
vars+=Variable*
tasks+=Task*
"}"
;
Variable:
"var" name=ID ":" type=JvmParameterizedTypeReference
;
Task:
{Task} "task" content=XTaskContent
;
XTaskContent returns xbase::XExpression:
{XTaskContent} block=XBlockExpression
;
Inferrer
class MyDslJvmModelInferrer extends AbstractModelInferrer {
#Inject extension JvmTypesBuilder
def dispatch void infer(Model element, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {
acceptor.accept(element.toClass("test.Model")) [
for (v : element.vars) {
members+=v.toField(v.name, v.type.cloneWithProxies) [
]
}
var i = 0;
for (t : element.tasks) {
members += t.toMethod("task"+i, Runnable.typeRef()) [
body = t.content
]
i = i + 1
}
]
}
}
Type Computer
class MyDslTypeComputer extends XbaseTypeComputer {
override computeTypes(XExpression expression, ITypeComputationState state) {
if (expression instanceof XTaskContent) {
_computeTypes(expression as XTaskContent, state);
} else {
super.computeTypes(expression, state)
}
}
protected def void _computeTypes(XTaskContent object, ITypeComputationState state) {
state.withExpectation(getPrimitiveVoid(state)).computeTypes(object.block)
state.acceptActualType(getTypeForName(Runnable, state), ConformanceFlags.CHECKED_SUCCESS )
}
}
Compiler
class MyDslCompiler extends XbaseCompiler {
override protected internalToConvertedExpression(XExpression obj, ITreeAppendable appendable) {
if (obj instanceof XTaskContent) {
appendable.append("new ").append(Runnable).append("() {").newLine
appendable.increaseIndentation
appendable.append("public void run()").newLine
reassignThisInClosure(appendable, null)
internalToJavaStatement(obj.block, appendable, false)
appendable.newLine
appendable.decreaseIndentation
appendable.newLine.append("}")
} else {
super.internalToConvertedExpression(obj, appendable)
}
}
}
Bindings
class MyDslRuntimeModule extends AbstractMyDslRuntimeModule {
def Class<? extends ITypeComputer> bindITypeComputer() {
return MyDslTypeComputer
}
def Class<? extends XbaseCompiler> bindXbaseCompiler() {
return MyDslCompiler
}
}
When I output a property, I think I get the reference/pointer of the closure instead of the expected return value.
For instance, for the following property: ${g.goalsAgainstAverage}:
<td header="stathdr5 stathdr${g.leagueId} stathdrgt${g.leagueId}_${g.gameTypeId}">${g.goalsAgainstAverage}</td>
Will output:
<td header="stathdr5 stathdr1 stathdrgt1_3">com.mgs.StatService$__tt__getSeasonStats_closure10$_closure24$_closure25#61df269d</td>
Here is the service generating the value (see calcGoalsAgainstAverage):
import grails.transaction.Transactional
#Transactional
class StatService {
def serviceMethod() {
}
def getSeasonStats(Long userId, Long seasonId){
def seasonRaw = Game.createCriteria().list{
...
}
def seasonStats = seasonRaw
.groupBy { it.leagueId }
.collect { leagueId, records ->
[
...
gameTypes: records.collect {
[
...
goalsAgainstAverage: {calcGoalsAgainstAverage(it.secondsPlayed, it.minutesPlayed, it.gameInMinutes, it.goalsAgainst)}
]
}
]
}
return seasonStats
}
double calcGoalsAgainstAverage(int secondsPlayed, int minutesPlayed, int gameInMinutes, int goalsAgainst){
...
}
}
You're returning a closure...
Either change:
goalsAgainstAverage: {calcGoalsAgainstAverage(it.secondsPlayed, it.minutesPlayed, it.gameInMinutes, it.goalsAgainst)}
To
goalsAgainstAverage: calcGoalsAgainstAverage(it.secondsPlayed, it.minutesPlayed, it.gameInMinutes, it.goalsAgainst)
Or, change
${g.goalsAgainstAverage}
To
${g.goalsAgainstAverage()}
I have the next code:
//models
case class Foo(name: String, age: Option[Int] = None)
//routing
trait FooRouting extends HttpService {
def index(foos: List[Foo]): twirl.api.Html = html.foo.render(foos)
val route =
path("") {
get { complete( index(Foo.all) } }
}
}
In index method, i render foo.scala.html template with Twirl.
I want test this behaviour:
//tests
class FooTests extends FunSpec with Matchers
with ScalatestRouteTest {
def actorRefFactory = system
val t0 = Foo("test0")
val t1 = Foo("test1")
it("test foo") {
Get() ~> r ~> check {
responseAs[List[Foo]] should be(List(t0, t1))
}
}
}
But i got error:
Tests.scala:49: could not find implicit value for evidence parameter of type spray.httpx.unmarshalling.FromResponseUnmarshaller[List[pack.Foo]]
[error] responseAs[List[Foo]] should be(List(t0, t1))
I define implicit method:
implicit val foo2response = new FromResponseUnmarshaller[List[Foo]] {
def apply(r: HttpResponse): Deserialized[List[Foo]] = {
???
}
}
But i do not know what i should write into body.
Thanks.