Wednesday, July 27, 2016

How to run Cucumber feature tests in android, quick steps for Android Studio 2.1





These steps are not for UI tests, if you want to do acceptance tests emulating user interaction with the UI better use Calabash.


  1. Create a new android project in Android Studio.
     
  2. Open build.gradle and add the following dependencies

    androidTestCompile 'junit:junit:4.12'
    androidTestCompile group: 'info.cukes', name: 'cucumber-java', version: '1.2.2'
    androidTestCompile group: 'info.cukes', name: 'cucumber-core', version: '1.2.2'
    androidTestCompile group: 'info.cukes', name: 'cucumber-html', version: '0.2.3'
    androidTestCompile group: 'info.cukes', name: 'cucumber-jvm-deps', version: '1.0.3'
    androidTestCompile group: 'info.cukes', name: 'gherkin', version: '2.12.2'
    androidTestCompile 'info.cukes:cucumber-android:1.2.0@jar'
    androidTestCompile group: 'info.cukes', name: 'cucumber-junit', version: '1.2.2'

    it must be that exact version in all cucumber libraries, the latest version doesn't work due to they are compiled with java8, and java8 is not supported yet in android (soon, soon, we hope)

     
  3. We need to setup in gradle that the tests will be executed using Cucumber. Add the instrumentation runner in build.gradle, in the defaultConfig setup

    defaultConfig {
        applicationId "my.application.package"    minSdkVersion 14
        targetSdkVersion 24
        versionCode 1
        versionName "1.0"    
        testInstrumentationRunner "cucumber.api.android.CucumberInstrumentation"
    }
     
  4. Create a new assets folder for the cucumber features in src/androidTest/assets
     
  5. This new folder is not recognized by gradle yet, set the new assets folder in build.gradle exactly, e.g. below the defaultConfig

    defaultConfig {
        ...
    }
    sourceSets {
        androidTest {
            assets.srcDirs = ['src/androidTest/assets']
        }
    }
     
  6. Create a new folder named "features" in the assets folder. All the feature files will stored be here (you can use subfolders). Example of a feature, can be on any file, cucumber doesn't care about the name of the file:

    Feature: Calculator
    
      Scenario Outline: a simple sum
        Given I have numbers 2 and 3
        When I sum
        Then the result is 5
     
  7. This is an important step. Create your tests in the subpackage "test" of your main package id, e.g. my.application.package.test

    A test example for the previous feature:

    @CucumberOptions(features = "features")
    public class CalculatorFeatureTest {
    
        private int mNum1;
        private int mNum2;
        private int mResult;
    
        @Given("^I have numbers (-*\\d+) and (-*\\d+)$")
        public void i_have_numbers_and(int n1, int n2) throws Throwable {
            mNum1 = n1;
            mNum2 = n2;
        }
    
        @When("^I sum$")
        public void i_sum() throws Throwable {
            mResult = mNum1 + mNum2;
        }
    
        @Then("^the result is (-*\\d+)$")
        public void the_result_is(int result) throws Throwable {
            assertEquals(mResult, result);
        }
    
    }

    The annotation @CucumberOptions specifies the folder inside the assets for all the feature files, in this case "features"
     
  8. Right click the package with the tests, and choose "Run tests in ..."
     
  9. You are done







Saturday, July 2, 2016

Be careful, Kotlin includes dead code in generated bytecode.



I enjoyed two Kotlin presentations. Both combined describe the best of this new language.






There is one thing not covered by those presentations, it is a tiny detail in how Kotlin generates the bytecode:

Kotlin inlined functions include dead code in the generated bytecode.



Not a big issue when using Proguard or similar tool to optimize/shrink the classes, but in in case of Android development sometimes is needed to avoid proguard optimization/shrink due to the complexity of the project, libraries, etc.

An example showing code and bytecode in Java and Kotlin


Let's see an example.  We want to log debug messages, but we dont want to include code for debugging purposes in the bytecode of the release build:
  • In java we call a log method inside a condition checking for a boolean constant, so the compiler ignores the code in the release build when the constant is false.
  • In Kotlin we use the advantage of inlined functions, we dont need to always include the condition when calling the log method. The function to log the message is the following

    inline fun debug(func: () -> String) {
        if (BuildConfig.DEBUG) {
            println(func())
        }
    }


We log the message inside a method named "doSomething"

Java
void doSomething() {
    if (BuildConfig.DEBUG) {
        System.out.println("This is a debug message");
    }
}

Kotlin
fun doSomething() {
    debug { "This is a debug message" }
}

+1 for Kotlin, cleaner code.

In java to have a cleaner code we could create a static utility method named "debug" and put the condition inside, but the compiler will include all the calls to "debug" in the bytecode of the release build. Even after optimizing with proguard the method calls will be removed, but not the parameters, depending on how many optimization passes we define in proguard.properties


Let's check now the bytecode generated by Java and Kotlin compilers.


To analyze the bytecode I use the plugin for IntelliJ/Eclipse made by the creators of the ASM library, the OW2 Consortium. I could use the Kotlin plugin included in IntelliJ in menu Tools -> Kotlin -> Show Kotlin Bytecode but it doesnt add an option to ignore the line numbers, unused labels and stack information.


Generated bytecode when DEBUG constant is true

Java
  void doSomething() {
    getstatic 'BuildConfig.DEBUG','Z'
    ifeq l0
    getstatic 'java/lang/System.out','Ljava/io/PrintStream;'
    ldc "This is a debug message"
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
   l0
    return
  }


Kotlin (useless bytecode is underlined)
  public final static void doSomething() {
    nop
    getstatic 'BuildConfig.DEBUG','Z'
    ifeq l0
    ldc "This is a debug message"
    astore 0
    nop
    getstatic 'java/lang/System.out','Ljava/io/PrintStream;'
    aload 0
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
   l0
    return
  }

+1 for Java.

Why? The difference is small but Kotlin includes some useless nops and the loading of the string "This is a debug message" is a bit dumb, loads the string, stores it, and loads it again.



Generated bytecode when DEBUG constant is false

Java
  void doSomething() {
    return
  }


Kotlin (dead code is underlined)
  public final static void doSomething() {
    nop
    iconst_0
    ifeq l0
    ldc "This is a debug message"
    astore 0
    nop
    getstatic 'java/lang/System.out','Ljava/io/PrintStream;'
    aload 0
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
   l0
    return
  }

+1 for Java, the java compiler ignores the code inside the condition, but Kotlin does a copy/paste of the code when inlining the function, not taking into account the value of the constant is always false.


A better approach using gradle flavors


What I recommend to do for Kotlin is, instead of checking for a constant, to use gradle flavors, the debug method in the flavor for the debug build shows the message, the debug method in the flavor for the release build does nothing.

Debug flavor Release flavor
inline fun debug(func: () -> String) {
    println(func())
}
inline fun debug(func: () -> String) {
}


Using it in this way we produce clean code and clean bytecode.


Kotlin Bytecode: Debug flavor
  public final static void doSomething() {
    nop
    ldc "This is a debug message"
    astore 0
    nop
    getstatic 'java/lang/System.out','Ljava/io/PrintStream;'
    aload 0
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
    return
  }

Kotlin Bytecode: Release flavor
  public final static void doSomething() {    
    nop
    return
  }



Kotlin adds a useless nop in the bytecode generated by the release flavor but is clean enough for our needs.


Are we solving a big issue here? Not really, but these small details help us to create clean code without adding an overhead in the compiled classes.









Tuesday, June 21, 2016

Git: How to move a folder to a new empty repository, with history included



http://cronicasdelula.blogspot.nl/2016/08/kotlin-incluye-codigo-muerto-en-el.html


I will not write an introduction of why we need to do this. This is how I did it, not sure if it is the best way but worked 100%:

I used the git commands described in this great article https://help.github.com/articles/remove-sensitive-data/

  1.  Two repos: REPO_OLD with the folder I want to move, REPO_NEW an empty repository where I will move the folder
     
  2. Copy everything (.git folder included) from REPO_OLD to REPO_NEW (another way is to clone REPO_OLD into a new folder REPO_NEW)
     
  3. DONT FORGET THIS: Remove the origin in REPO_NEW: git remote rm origin
     
  4. Delete in REPO_NEW all folders you DONT need. E.g. folder name is FOLDER then

    git filter-branch --force --index-filter ' git rm --cached --ignore-unmatch -r  FOLDER/ ' --prune-empty --tag-name-filter cat -- --all

    do it with all the folders one by one, at the end only the folder you need should be in REPO_NEW. If some folders still exist it is due to some files were not added to git, you can delete the folders manually, they are not in the git history anymore.
     
  5. Now set origin in REPO_NEW to the remote repository where you want to push this new repo.
     
    E.g. git remote add origin git@bitbucket.org:someuser/REPO_NEW.git 
     
  6. Push everything forcing overwrite history: git push origin --force --all
     
  7. Ok, it is copied, but not moved. Just delete the folder in REPO_OLD using the same command you used in step 4.
     
  8. Done



Sunday, May 15, 2016

Released a new android app: Radar Stats for LoL

Hi all,

I created a new app to analyze my games in League of Legends. I hope you enjoy it as I do.

The link to Google Play: https://play.google.com/store/apps/details?id=ar.ignaciotcrespo.lolradar

And the webpage: http://lolradarstats.com/

Some screenshots:







Later I will describe which libraries I am using in the app.

Any feedback is welcome.

Lula



Monday, February 22, 2016

New Experimental Project: Radar Stats for League of Legends


I play League of Legends. A lot. It is my new drug (I started 3 years ago). I enjoy it more than any other game. Update: I dont play it anymore, I have a family :)

There are many applications on internet showing the game statistics: kills, deaths, assists, damage, etc. but none of those applications show the stats in the exact way I need it. What I want to see:

- A radar spiderweb of both teams, showing all kind of stats, and the evolution during the entire game. Similar to the radar graphs used by basketball websites to analyze the game.
- A map showing how both teams moved, the path they followed, were they did the kills, the area covered by both teams, and more. To do this LoL API has data in frames, separated in minutes, so it is not exact but it gives an idea of how the enemy jungle started (and killed me :0 ).
- Open the match details in the official lol history, or in LolKing.net
- Share the match details with friends

I created an android app with those features. The UI is bad, but I am focused on the functionality, after every game I analyse the graphs and discover my mistakes, the good moves of my enemies, and learn. I can not say I became a better player because of the app, but I am playing better trying to avoid the same mistakes the graphs showed to me. Sometimes it works, and I enjoy watching the graphs and the maps many times.

The LoL API doesnt return all stats in the timeline (e.g. we can not see the evolution of the total damage), but it has enough data to play with it.

I uploaded an alpha build to the store, you can download here it after joining as an alpha user https://play.google.com/apps/testing/ar.ignaciotcrespo.lolradar

UPDATE: I released it some months ago, the link is https://play.google.com/store/apps/details?id=ar.ignaciotcrespo.lolradar

For developers, some useful libraries I used to create the app:

- MPAndroidChart: excellent library to display charts in android.
- Picasso: very good image loader, very easy to use. Some issues present (memory leaks sometimes) but nothing critical.
- CircularImageView: show circular images with almost no code.
- GSON: to parse the LoL statistics in json format, and convert them to business objects.
- Guava: always useful, maybe too big for android, but this app is small.


Screenshots: (UPDATE: these screenshots are old, the new app has a different UI)


A radar chart showing the stats of each line, both teams compared




You can select 2 players and compare their gold, kda, wards, cs and objectives.




A heatmap shows the position of all players during the match. It can be changed to different kind of graphs, and see the evolution on every minute during the game.




You can select 2 players in the map and choose "Show path" to see live the path they did during the entire game.

https://goo.gl/JJHSmb



And of course the list of recent matches.




I am still working on it. It is an alpha so it has bugs. There are many things to improve, any feedback is welcome.


Enjoy Lol.


PD: if you want to play with me, my nick is "nippur" in EUW.




Sunday, January 26, 2014

Just when you thought you knew a lot about development...

Just when you thought you knew a lot about development someone that knows more punch you directly in the face with a few wise words.

A friend recommended me "Clean Code" and "Clean Coder", by Robert Martin.

http://www.objectmentor.com/omTeam/martin_r.html

I feel like a child learning everything again. I love these books, it is the kind of technical thing that you need to read before going to sleep.







Wednesday, November 14, 2012

Android SDK Manager can't find latest updates!

I had a nice surprise today. After updating the ADT plugin in Eclipse it says that I must update the android tools.

Ok, one more time I opened the SDK Manager and searched for the updates. But wait... there is no updates. And Eclipse doesn't work! WTF?

"It must be a bad nightmare, take it easy" I think. Just do the obvious thing, close the SDK Manager and open it again. Stupid solution, it doesn't work.

Ok, something is bad, so I enter to the preferences and what I see is "Cache size" with the option "Delete cache". Oh yea! Now it works. God exists.

Stupid cache, you think you know everything, but I am better than you :D