If the Application has a Custom Application object. It is needed to annotate this with #HiltAndroidApp
ex:
#HiltAndroidApp
class AppCore: Application
Appcore has some initialization logic which is needed for the app to run
Now in the Instrumentation tests We also need to Extend the custom Application object.
#CustomTestApplication(AppCore::class)
interface HiltTestApplication
This gives an error #CustomTestApplication value cannot be annotated with #HiltAndroidApp
Is there any other way of using HILT in instrumentation tests with custom Application objects
public abstract interface HiltTestApplication {
^
#CustomTestApplication value cannot be annotated with #HiltAndroidApp. Found: AppCore
As suggested in the issue tracker. Can you abstract your initialization logic into a base class, say BaseAppCore : Application then in your prod application extend it #HiltAndroidApp AppCore : BaseAppCore and then for tests make Hilt generate a test app based on your abstract one, #CustomTestApplication(BaseAppCore::class) interface AppCoreTestApplication. It might be best to file this issue in https://github.com/google/dagger/issues
You will need to create a new class with the #HiltAndroidApp annotation, which would be different from the one you will use in your tests.
open class AppCore: Application
{
// Existing code.
}
#HiltAndroidApp
class ProdAppCore : AppCore
{}
#CustomTestApplication(AppCore::class)
interface HiltTestApplication
If you are using Robolectric, you can set:
application = $packageName.HiltTestApplication_Application
And in your AndroidManifest.xml, set:
<application
android:name="$packageName.ProdAppCore"
where $packageName is the package where ProdAppCore and HiltTestApplication class have been defined.
This is also discussed here: https://github.com/google/dagger/issues/2033
Related
Thank you all so much! I just started in Kotlin which probably should be called the K language (like C and F), and have found so many solutions here on this site...it's awesome!
I have an independent class file called AppTime.kt and it's declared in the AndroidManifest.xml file:
<application
android:name=".AppTime"
class AppTime : Application() {
fun burntToast(sMsg: String) {
Toast.makeText(this.applicationContext, "!", Toast.LENGTH_LONG).show()
}
}
It doesn't run when called anywhere from a Fragment class:
class FirstFragment : Fragment() {...
AppTime().burntToast()
I've tried every approach using parameters for the Toast following makeText(...
and then to call it from a Fragment with or without context or string parameters.
Is it the type of class I have?
Functions defined inside a class can only be called on an instance of that class, as you already found.
But you cannot simply instantiate an arbitrary Application and expect it to work. Android does a lot of behind-the-scenes setup of framework classes before they are usable. Any Application or Activity that you instantiate yourself is useless. You have to use the instances that are provided to you through the lifecycle of the Activities that get launched in your application.
If you want to call this function from your Fragment, you will have to get an instance of your application, which you can get from its associated Activity. Since the Activity class doesn't know about your specific subclass of Application, you must also cast the application to your specific subclass to be able to call its unique functions. You can get the Activity by using requireActivity().
(requireActivity().application as AppTime).burntToast()
I try to start unit testing a mid size Xtext project.
The generator currently relies on some external resources that I would like to mock inside my test. Thus, I inject the needed object via #Inject into the Generator class.
e.g in pseudocode:
class MyGenerator implements IGenerator{
#Inject
ExternalResourceInterface resourceInterface;
...
}
I create the actual binding inside the languages RuntimeModule:
class MyRuntimeModule{
...
#Override
public void configure(Binder binder) {
super.configure(binder);
binder.bind(ExternalResourceInterface .class).to(ExternalResourceProductionAcess.class);
}
...
}
This works fine for the production environment.
However, in the generator test case, I would like to replace the binding with my mocked version, so that the following call to the CompilationTestHelper uses the mock:
compiler.assertCompilesTo(dsl, expectedJava);
Question:
Where do I tell guice/Xtext to bind the injection to the mock?
If you annotate your test case with RunWith and InjectWith, your test class will be injected via a specific IInjectorProvider implementation.
If that injector provider uses a custom module (like you have shown), the test case gets injected using that configuration. However, you have to make sure you use this injector throughout the test code (e.g. you do not rely on a registered injector, etc.).
Look for the following code as an example (have not compiled it, but this is the base structure you have to follow):
#RunWith(typeof(XtextRunner))
#InjectWith(typeof(LanguageInjectorProvider))
public class TestClass {
#Inject
CompilationTestHelper compiler
...
}
I'm not sure if there's something really basic that I'm missing, but I can't figure out how to use WSClient. I've seen all of the examples saying you need to pass the WSClient to a class as a dependency, which I've done, but when I run the program what do I actually pass to my class?
For example, my class signature is:
class myClassName(ws: WSClient)
But when I instantiate the class what do I actually pass to it? I'm also happy to ignore the Play! framework stuff if that makes it easier and just use SBT to run it (which I'm more familiar with).
It's unclear where you might be using a WSClient, but it is recommended that you let the Play framework 'manage' the instance of the client. When you instantiate your application, it gets injected:
class Application #Inject() (ws: WSClient) extends Controller {
...
}
What that means is that inside the ... you have access to ws as a value. You can instantiate myClassName using it:
class Application #Inject() (ws: WSClient) extends Controller {
val myclass = myClassName(ws) // passes the injected WSClient to myClassName
}
Or you can write a function that returns the WSClient, so some other area of your code can call into your Application object to get a object handler for it.
But the key is that the Application object gets that handle because of injection, which is the #Inject annotation.
If you need to generate a WSClient and manage it manually, there are good instructions here. The recommended implementation is reliant on Play! framework libraries, but doesn't depend on the Application.
I'm new to the testing environment,i have small confusion in adding the class file,i want to test the restful web services
Which class file to include in the Class under Test in the junit test case creation?
Whether the dao class or bean class or service class.
It doesnt matter, you could skip it. The class-under-test is for writing a single unit test for a single class, where the wizard creates the test method stubs for the methods of the class for you.
When you want to test a REST service, you don't need that and could skip that part. Just create the test and name the test method according to the use case or scenario you want to test.
Using JUnit4, the test itself is even a plain java class, the only thing that makes it special are #Test annotated methods. So you don't even need that entire wizard.
But in case you want to UnitTest the service, you select the service class itself (i.e. the Jax-RS service class annotated with #Path)
I am new to using Mockito and I am running through an example test class written in our GWT project.
At some places ,in order to get a Mock we used Mockito.mock(SecurityDao.class)
but in other places in the same test class we instantiated other classes using the "new" keyword.
I think that in order to mock a class i need to pass in the interface as the parameter to Mockito.mock ,and if my class does not implement an interface then i need to use the "new" keyword to instantiate the class.
Is this correct?When should i really use Mockito.mock??
Thanks
Always use Mockito#mock() when creating an object other than that under test. Mockito can create mocks for interfaces and classes.