End to end test for android app with dynamic feature module . How to? - android-testing

Android project structure :
-app module
-featureA dynamic module -> depending on app module
-featureB dynamic module -> depending on app module
Use Case :
I want to write end to end intrumentation test for my application
Issue :
Since , dynamic module classes are not available to app module or other modules . It seems impossible to write end to end test for the application covering all the features .
So, please let me know what can be done here .
Is it possible or not ??
Any work around ??
How do big companies with dynamic feature do it ??

In case you need to call some classes of dynamic features, you can do so by using Reflection or Service Locator mechanism.
Please see this answer for more details around that: Call dynamic feature code from base module
If you don't need to call those classes yourself in your end to end test, you can create a universal APK which contains all the modules and when the main app module will check if the feature module is installed, it will come out as true and it can then itself call the different methods of the dynamic module by Reflection or Service Locator pattern.

Related

Problem with constant autoloading in a Rails project (works occasionally)

I am working with a Rails project and don't quite understand how Rails autoloading works in my particular case. I read some articles about Rails' autoloading and its pitfalls but those didn't really help me
I am building a processor for tasks (exercises). Each task has its custom processor class in Tasks::<TaskName>::Processor that mixes in module Tasks::Processor that contain shared code for task processors. Processors contain class Get (for processing GET requests) located in Tasks::<TaskName>::Processor::Get that mixes in Tasks::Processor::Get containing generic Get's code.
I've simplified the code a little bit so it's easier to understand and removed all the business logic but it's still enough to reproduce the problem.
So the problem is:
when I run Tasks::TaskOne::Processor.new.get it works fine, but if I run Tasks::TaskTwo::Processor.new.get after that it throws an error: NoMethodError: undefined method `new' for Tasks::Processor::Get:Module. It also works the other way round: if I run TaskTwo's processor's code first then it works fine but the TaskOne's processor will throw the error. It just fails to find the specific implementation of Get and instead finds the generic module and tries to instantiate it which is obviously impossible.
Here is the code together with the structure.
Shared code:
app/models/tasks/processor.rb:
module Tasks
# generic Processor (mixed in by custom processors)
module Processor
# ...
end
end
app/models/tasks/processor/get.rb:
module Tasks
module Processor
# generic Get
module Get
# ...
end
end
end
TaskOne's code:
app/models/tasks/task_one/processor.rb:
module Tasks
module TaskOne
# processor for task_one
class Processor
include Tasks::Processor # mix in generic task processor
def get
Get.new.call
end
end
end
end
app/models/tasks/task_one/processor/get.rb:
module Tasks
module TaskOne
class Processor
# task_one's processor's custom Get
class Get
include Tasks::Processor::Get # mix in generic Get
def call
puts "in task_one's Processor's Get"
end
end
end
end
end
And practically identical code for the TaskTwo:
app/models/tasks/task_two/processor.rb:
module Tasks
module TaskTwo
# processor for task_two
class Processor
include Tasks::Processor # mix in generic task processor
def get
Get.new.call
end
end
end
end
app/models/tasks/task_two/processor/get.rb:
module Tasks
module TaskTwo
class Processor
# task_two's processor's custom Get
class Get
include Tasks::Processor::Get # mix in generic Get
def call
puts "in task_two's Processor's Get"
end
end
end
end
end
It has most likely something to do with Rails' autoloading, because when I use plain ruby and manually require all the files and try to run the code the problem doesn't happen.
Could you, please, explain why it works like this and tell me what the best way to avoid this problem is? Seems like Rails doesn't like the fact that I have a class and a module with same name and it gets confused, but I thought it shouldn't be a problem as they are in different namespaces.
I could have just named the generic class something different, but I'd really like to understand why using the same class name for both specific implementation and generic one only works for the first thing to load but not for the next. Thank you very much for your help!
P.S. my version of Ruby is 2.5.1 and Rails version is 5.2.1
I was literally reading about autoloading yesterday. Your problem is the same as the one outlined here:
https://guides.rubyonrails.org/autoloading_and_reloading_constants.html#when-constants-aren-t-missed
Basically, any time you write Get.new.call, you need to be more specific. It doesn’t know which Get to use in the tree of possible Gets. The first time you call it, it hasn’t had to load up more than one Get class, and so it actually finds the right one. After that call, you’ve now auto loaded MORE classes, and now things start to get dicey. You need to either qualify your Get to be more specific, and/or use require_dependency to force the right classes to be loaded in. However given your case, I think require_dependency will just make it fail every time, since you’ll now have all of the classes loaded up.

Call functions/variables/tables from a separate file in Lua

I'm currently working on a fairly detailed project in Lua, specifically using LOVE2D. I'm currently using require'file' in order to access different parts of my project, but this seems like very poor form. I've ran into the problem of overwriting tables from different files with the same name. There must be a professional, cleaner way to do this, but I haven't been able to find one. Can somebody help me?
Using require is the right way to do it.
Think of a module as a function that gets executed when it's loaded. It's return value is cached and returned on subsequent require calls. Just like you would use local variables to limit the scope in a function, you can do the same in a module.
I'm guessing your modules are implemented as global tables:
mymodule = {}
function mymodule.foo()
return 'bar'
end
And you load the module like:
require 'mymodule'
Just change the module table to a local variable and return it:
local mymodule = {}
function mymodule.foo()
return 'bar'
end
return mymodule
Then, you can load the module with any name you choose:
local mymodule = require 'mymodule'
Since you don't create global variables you don't have to worry about overwriting other modules.
The example used above is from the Module Tutorial on the lua-users.org website. Check it out for more info about creating modules. Also, How to write Lua modules in a post-module() world is also worth reading.

Create Generic Module in rails

I'm a newbie to rails. I have created a reports module for a particular project. Now, we want to make it generic across all project like a reports gem. My question is not about how to create & use gem. My questions is "how to make a generic reports lib". For eg. I have a helper module in reports,
module Libquery
module Helper
include QueryConstants(which is dynamic - based on the project)
#methods
end
end
end
My approach: each project will include LibQuery::Helper and also it will include its own constants file.
module ProjectX
module Query
module Helper
include Libquery::Helper
#nothing - inherit all helper methods in libquery
end
end
end
But I'm wondering if that's the most elegant way of doing things ? Or any better way to do it?
First of all, all modules must be capitalized:
module MyModuleName
Second, to use a lib it's best to include it in autoload_paths (in your application.rb file) like this
config.autoload_paths += %W(#{Rails.root}/lib/my_shared_libs)
This means rails will load it automatically, and you'll have available 'out of the box'.
Third, external modules shouldn't depend on project-based modules and classes, since the whole point is to make them easily reusable.
So it boils down to this:
#/lib/my_shared_libs/fun_things.rb
module FunThings
... your code
def laugh
puts 'haha'
end
end
#/models/user.rb
class User
include FunThings
end
User.new.laugh # => 'haha'

override lib module method for specific rails environment

I've got a library module I'd like to override based on the rails environment I'm running in
Module is located in lib/package/my_module.rb:
module Package
module MyModule
puts "Defining original module"
def foo
puts "This is the original foo"
end
end
end
I have been able to partially solve with the info at Overriding a module method from a gem in Rails - specifically, in my environments/dev_stub.rb:
Package::MyModule.module_eval do
puts "Defining override"
def foo
puts "This is foo override"
end
end
(The other solution at that link seems to cause errors when rails tries to lookup other classes related to package)
Now, this seems to get me most of the way there, and works if I set
config.cache_classes = true
...but I want to use this as a stub development environment, and the comment recommendation on this value for a dev environment is to use false... in which case the override only works the first time the module is included, and any subsequent times, it uses the original.
My question: Am I going about this the right way? I could hack up the lib module itself to conditionally override based on RAILS_ENV, but I'd like to keep it cleaner than that...
Edit
My use case for this is to reference it from a controller function. If I have
class SomethingController < ApplicationController
def show
Package::MyModule.foo
end
end
and config.cache_classes=false (which I ideally want since it is a development environment), and access the action through my web browser (http://localhost/something/show) then the first time I hit it, my override is loaded and it works, but the second and any subsequent times, the original library class is reloaded (outputs "Defining original module" on my console without "Defining override"), and the override is lost.
Another alternative I tried was add something like config.load_paths += %W( #{RAILS_ROOT}/lib_patch/#{RAILS_ENV}) to environment.rb - but defining the same module/class didn't quite work without putting in an explicit hook in the original library to basically load the patch if it existed
Edit 2 (in response to #apneadiving answer)
I've tried doing this without module_eval, and just using the following in development_stub.rb:
require 'package/my_module'
module Package
module MyModule
puts "Defining override"
def foo
puts "This is foo override"
end
end
end
The problem I initially had with doing this is that Rails no longer automatically finds all content in my lib directory, and I need to sprinkle 'require' statements throughout all other lib files (and my controllers that reference the libs) to cover all of their dependencies. Although this is all done, it does work, but it also has a similar effect as config.cache_classes=true does, in that all the lib classes are not reloaded on change, even in my regular development environment that does not have a monkey-patch (since all the 'require' statements are added).
Setting config.cache_classes=true in dev_stub.rb and using module_eval to define the patch as described in the question seems the way to go for what the goal is here - to create an environment specific patch for a module that doesn't impact the other environments in both code path and Rails class loading behavior.
you could simply override the module and it's instance without module_eval.
I guess your module is included as a Mixin and it's methods aren't impacted by your monkey patch.
That's where alias_method_chain comes in action.
Look at this great article to get how you should use it to fit your needs.

How do I properly use mock functionality for testing purposes in Rails?

I am new to using mixins, and I am more familiar with Java-based dependency injection.
Let's say I use a mixin module to provide database connectivity for a class, as described at http://fabiokung.com/2010/05/06/ruby-and-dependency-injection-in-a-dynamic-world/ :
module ConnectionProvider
def connection
# open a database connection and return it
end
end
# reopening the class to mix the module in
class Repository
include ConnectionProvider
end
This allows me to do this:
class Repository
def find(id)
connection.execute("SELECT ...")
end
end
Now I don't have to pass a ConnectionProvider object in via the Repository initializer.
Let's say I want to use a mock version of ConnectionProvider for testing purposes, and so I want to include MockConnectionProvider in Repository instead of ConnectionProvider. Both ConnectionProvider and MockConnectionProvider provide the method connection. Here is how I think this is supposed to be done.
For my normal Rails app
In environment.rb:
require File.dirname(__FILE__) + "/../lib/repository"
For my test scripts
In my test files:
require File.dirname(__FILE__) + "/../lib/repository_mocked"
Is this correct? If not, can someone provide a link to an article demonstrating the proper way?
You should use a mocking library to do this kind of things. I usually use mocha which has a good interface, with that you can write code like
mocked_value = # anything you want
Repository.any_instance.stubs(:find).returns(mocked_value)
So every call to Repository#find will return the mocked_value
Other mocking libraries are:
rspec
flexmock
You can just mock 'connection' method.
As module has been included to the class its methods are treated as methods of this class.
If you'd like to mock a bunch of related methods you can rewrite your class which uses an instance of ConnectionProvider class (yes, change it to class from module) for example. So in this way you can mock this ConnectionProvider instance object.
UPD: you should not mess with files for mocking. Use special mocking tools as Fabio told you. ;)

Resources