I have written a custom TestRule to use with my Android test suite. It populates a table in the database used by the app under test. Now I need to use this DataRule along with ActivityTestRule. Can I have two fields of my test class annotated with #Rule? How do I control the order in which the rules are applied?
Background:
The Android API provides a TestRule for starting an Activity which is the core class for every app with a UI. My app has a database and I have several tests which require the database to be pre-populated with some known data. Previously, with JUnit3-based tests, I used an abstract superclass to centralize the code which prepares the database and then I extended this superclass for different test cases. Now I am trying to implement the same logic using JUnit 4. I learned recently that test rules are one way to provide logic which is reused across tests, so I am trying to move the logic from my superclass to a test rule. Is this an appropriate way to achieve my goal?
You certainly can have multiple #Rule fields in a single test. I'm not sure what the default ordering of rule application is, or if it's even well-defined. However, if ordering is important you can control it with a RuleChain
which allows you to define an order on how rules are applied when you have multiple rules in a test case.
From the Javadoc...
#Rule
public RuleChain chain = RuleChain
.outerRule(new LoggingRule("outer rule")
.around(new LoggingRule("middle rule")
.around(new LoggingRule("inner rule");
RuleChain is deprecated and since 4.13 you can make use of order parameter in Rule.
org.junit.Rule annotation has a parameter "order" which you can use to order the Rules in one file.
check the doc in the link below
Rule.java
If you're using JUnit for your tests, which I personally recommend, it's not recommended to have multiple rules in the same file, because a Rule is a unit of your test, and as you're doing unit tests, you should have just one Rule per file.
If you need to create some sort of data before you run your tests you should use the #Before and then load the necessary information.
More on this can be found here: http://junit.sourceforge.net/javadoc/org/junit/Before.html
If you have to load the same data in multiple classes, I would recommend you to create a class with your logic, extend that class in your test class and then create a method annotated with #Before an call your super class method.
Hope that helps
Related
My app includes many helper classes like the next ones:
A class TMHttp with an "DownloadFile" or "IsOnline" methods (among others).
A TMEmail class with a "SendEmail" method.
A ImageHelper class with a "TakeScreenshot" or "CropBitmap" methods.
TMImport/TMExport classes with "ImportData" and "ExportData" methods.
A TMSession class with "LoginUser", "LogoutUser" and more such methods.
A TMUtils class with methods like "GenerateRandom".
A TMDialog class with methods like "CreateYesNoDialog" ... and many more.
And what I'd need to know -regarding DI- is if I have to inject them where needed -like I do with repository and services- or just create an instance of them. Do I have to inject every class in my app?
I believe there is no strict answer to this question because it depends on the architecture of your project, the principles the team is using, the purpose and the complexity of the helper/util class, etc.
You need to decide it for each such helper/util class particularly, guided by the following advantages of Dependency injection:
Reusability of classes and decoupling of dependencies: It's easier to swap out implementations of a dependency. Code reuse is improved because of inversion of control, and classes no longer control how their dependencies are created, but instead work with any configuration.
Ease of refactoring: The dependencies become a verifiable part of the API surface, so they can be checked at the object-creation time or at compile time rather than being hidden as implementation details.
Ease of testing: A class doesn't manage its dependencies, so when you're testing it, you can pass in different implementations to test all of your different cases.
For example, I would argue like this:
A TMUtils class with methods like "GenerateRandom"
Likely, it's a quite simple helper method that basically can have a standard single implementation; it doesn't depend on other libraries, so I can freely use it without DI.
A class TMHttp with an "DownloadFile" or "IsOnline" methods (among others).
It's heavy and it depends on a lib and Android SDK then it makes sense to inject.
And so on.
I have a few "connected" tests that are only relevant to run on a specific device model or on a specific brand and should be skipped on other brands/models.
I may be missing something, but this kind of filtering seems not possible out-of-the-box with AndroidJUnitRunner (by using annotation and/or passing appropriate arguments to it).
So, I was thinking to extend the AndroidX test framework to support this kind of filtering. In the end, I would like to be able to filter test with something like this
#TargetDeviceFilter(brand="SAMSUNG",model="XCover3")
#Test
public void myTestToRunOnSamsungXCover3DeviceOnly(){
...
}
My question: is there any way to accomplish this kind of filtering without extending AndroidX test framework? And if writing my own AndroidJUnitRunner and/or my own annotations is required, how should I start ?
I found a few interesting base classes that I may need to extend like :
androidx.test.internal.runner.TestRequestBuilder
androidx.test.internal.runner.TestRequestBuilder.DeviceBuild
but as those classes are in a "internal" package: attempting to extend them is probably not a good idea?
Any advice on how to deal with that problem is welcome.
I think, you may use org.junit.Assume.
Create a helper class DeviceHelper to detect mobile device informations for convenience.
Your test logic will be executed only if the assumption is correct.
#Test
public void myTestToRunOnSamsungXCover3DeviceOnly() {
// adapt this part to your business need
org.junit.Assume.assumeTrue(
DeviceHelper.isBrand("SAMSUNG") &&
DeviceHelper.isModel("XCover3")
);
// i.e. you can filter whatever you want test's according to device sdk_int
assumeTrue(SomeHelper.getDeviceSdk() >= 21);
// your test code
}
Recently at my company a debate started after reviewing a different approach for writing heavy duty classes.
A big Java class holding component specific logic (no standard OOP principles made sense) had to be rewritten in Kotlin. The solution provided was splitting the logic in categories and the categories into separate files with internal extension functions to the main class.
Example:
Main.kt
class BigClass {
// internal fields exposed to the extension functions in different files
// Some main logic here
}
BusinessLogic.kt
internal fun BigClass.handleBussinessCase() {
// Complex business logic handled here accessing the exposed internal fields from BigClass
}
What are your thoughts on this? I haven't seen it used anywhere maybe for a good reason, but the alternative of thousand lines classes seems worse.
You have to consider that an extension function is nothing more than a function with an implicit first parameter which is referenced with this.
So in your case you'd have something like:
internal fun handleBussinessCase(ref: BigClass)
which would translate to Java as:
static void handleBussinessCase(BigClass ref)
But this could be assumed to be a delegate pattern, which could be encapsulated much cleaner in Kotlin as well.
Since the properties have to be internal anyhow, you could just inject these as a data class into smaller use-cases. If you define an interface around these (which would make the properties public though), you could create a delegate pattern with it and still reference each property with this in your implementation.
Here are some thoughts on making extension functions for the class:
It will be a utility function that will operate with the object you're extending, it will not be an object function, meaning that it will have access to only public methods and properties;
If you're planning to use class that being extended in unit tests, these methods (extensions) will be harder to mock;
Most likely they wont behave as you expect when used with inherited objects.
Maybe I missed something, so please read more about extensions here.
I was wondering if it was good practice to subclass the test cases on Android. I mean, I need to test a lot of Parcelable objects and I could create a class like GenerericParcelableAndroidTestCase to test all these objects.
I also have a problem implementing it, I have something like this:
public class GenericParcelableTest extends AndroidTestCase {
private Parcelable p = null;
GenericParcelableTest(Parcelable p) {
this.p = p;
}
public void testDescribeContents() throws Exception {
assertEquals(0, p.describeContents());
}
}
And that:
public class AttachmentTest extends GenericParcelableTest {
public AttachmentTest() {
super(new Attachment());
}
}
Attachment implements Parcelable of course.
It returns me this error:
junit.framework.AssertionFailedError: Class GenericParcelableTest has no public constructor TestCase(String name) or TestCase()
I mean, I know that I created no empty constructor but why would I need one?
And generally, is there some known issues with this approach? If not why is there very few article on this topic on the internet (and actually some say even that it's not a good idea).
I have this conversation quite often when introducing new team members to unit testing. The way I explain it is by stating that your tests are first class citizens of your code base (no pun intended), they are susceptible to the same technical debt as any other part of your code base and have equivalent (maybe more?!) importance as that of the runtime code.
With this mindset, the questions begins to answer itself; if it makes sense from an OO perspective to use inheritance (i.e. your subclass is a insert name of test superclass) then subclass away. However, like any abuse of inheritance ever, be careful...the minute you add a test case that doesn't rely upon that superclass behaviour you may have a code smell.
In this scenario, it's likely (perhaps 90% of the time?) it is a separation of concern issue within the code being placed under test, i.e. the "unit" under test isn't actually (one) unit but has combinatorial behaviour. Refactoring that code to do one thing would be a good way of allowing your super-class test case to live on. However, watch this super class test case like a hawk...the minute you see booleans being added to signatures to "allow that similar but not the same" test case to run under your once unpolluted super class then you have a problem, a tech debt problem that is no different to your runtime code.
At last check AndroidTestCase depends on an Activity context so it's likely best described as an integration test which tend to regularly have boilerplate super-class test behaviour. In this case, try to narrow the focus of your superclass to the use case under test...i.e. extends LoginUseCase or extends LoginScenario to better "bucket" those subclasses in the first instance. This will help guide would be extenders as to whether they should be using it for their non-login scenario. Hopefully, conversation will ensue and tech debt accumulation be avoided!
Regarding your error, in JUnit3 do what #Allen recommends, if moving to JUnit4 with something like Robolectric then explore using Rules as well as #BeforeClass.
Personal note
I have only felt the need to write test super classes for pseudo-unit tests that mock an API end point (akin to MockWebServer if you are familiar with that product) and DAO integration tests whereby an in-memory db is started and torn down over the lifecycle of each test (warning - slow (but useful) tests!)
junit.framework.AssertionFailedError: Class GenericParcelableTest has no public constructor TestCase(String name) or TestCase()
You get this error because JUnit needs to be able to construct an instance of your test class. It only knows how to do this using no-arg, or single string constructors.
Instead of performing initialization in your constructor, you should put it in the setUp() method. This will let you use the default constructor while still initializing the object before the test method is called.
I have to build an app with sqlite usage. Now I want to write my unit tests. These unit tests should test my class SQLiteBridge. SQLiteBridge provides DAOs for every child class of Model.
Now I got the problem that I need a context to create my SQLiteBridge. SQLiteBridge creates and handles a SQLite database on the system..
Where to get the Context-Object from?
My setup is like here (so I'm using Junit4 [thanks god]):
http://tools.android.com/tech-docs/unit-testing-support
EDIT: I hope there is a way like the old AndroidTestCase to extend without losing Junit4. :)
As described here: https://code.google.com/p/android-test-kit/wiki/AndroidJUnitRunnerUserGuide
Use the InstrumentationRegistry to obtain the context.
However if you call InstrumentationRegistry.getContext() directly you may get an exception opening your database. I believe this is because the context returned by getContext() points to the instrumentation's context rather than that of your application / unit test. Instead use InstrumentationRegistry.getInstrumentation().getTargetContext()
For example:
#RunWith(AndroidJUnit4.class)
public class SqliteTest {
Context mMockContext;
#Before
public void setUp() {
mMockContext = new RenamingDelegatingContext(InstrumentationRegistry.getTargetContext(), "test_");
}
}
The RenamingDelegatingContext simply prefixes the file/database names with test_ to prevent you from overwriting data that you may have in the same simulator.
jUnit 4 (and perhaps other versions of jUnit) and androidx use:
ApplicationProvider.getApplicationContext();
See: Android Documentation