samedi 14 novembre 2020

How to test asyncronous methods, in Rspec?

I have several Ruby methods that call methods from a library written in C++, via FFI gem. Some of the C++ methods involve spawning new threads inside a native library, others not.

The ruby methods look, basically, like this:

   my_params = create_params_for_method1()
   MyModule::method1(context, my_params) do |result|
     puts "result is: #{result}"
   end

All works fine.

A difficulty I have is that how to test these asyncronous methods? Some methods return value almost immediately and there's no issue with testing them:

expect { |b| MyModule.method1(my_context, my_params, &b) }.to yield_control
MyModule.method1(my_context, my_params) { |r| @result = r }

expect(@result).to eq "some_result123" # OK

But others keep sending data in a loop and therefore can't be tested in this way:

expect { |b| MyModule.method1(my_context, my_params, &b) }.to yield_control # error
MyModule.method1(my_context, my_params) { |r| @result = r }                 # error

expect(@result).to eq "some_result123"                                      # @result is still nil

I could insert sleep N in a rspec test, but this be a sensible approach?

# expect { |b| MyModule.method1(my_context, my_params, &b) }.to yield_control
MyModule.method1(my_context, my_params) { |r| @result = r }                


sleep 10

expect(@result).to eq "some_result123"            # not nil, but...

How long in seconds should I N be so that it'll always pass? The more the better, but how long? How would I guess?

Also, it's a hack, isn't it? Also, in some cases it'll keep sending data from a native library multiple times. How would I make sure that I've received it all, in a test?

And a test isn't supposed to take a long, undetermenistic time to test a method, is it?

What's the approach in such a case?

Aucun commentaire:

Enregistrer un commentaire