SlideShare a Scribd company logo
@AlexeyBuzdin
GDGRiga.lv JUG.lv
RigaDevDay.lvCitadele.lv
What does Android need?
UI
Tests
Integration
Tests
Unit Tests
UI
Tests
Integration
Tests
Unit Tests
Effort
Effort Cost
UI
Tests
Integration
Tests
Unit Tests
UI
Tests
Integration
Tests
Unit Tests
Effort Cost
Unit Test
๏ Uses simple JUnit
๏ Runs on JVM, not on a device
๏ Lightning fast (5k test in 10
seconds)
๏ Needs Android SDK Stubs
static protected void markConflicting(ArrayList<ScheduleItem> items) {
for (int i=0; i<items.size(); i++) {
ScheduleItem item = items.get(i);
// Notice that we only care about sessions when checking conflicts.
if (item.type == ScheduleItem.SESSION) for (int j=i+1; j<items.size(); j++) {
ScheduleItem other = items.get(j);
if (item.type == ScheduleItem.SESSION) {
if (intersect(other, item, true)) {
other.flags |= ScheduleItem.FLAG_CONFLICTS_WITH_PREVIOUS;
item.flags |= ScheduleItem.FLAG_CONFLICTS_WITH_NEXT;
} else {
// we assume the list is ordered by starttime
break;
}
}
}
}
} https://github.com/google/iosched
@Override
public void displayData(final SessionFeedbackModel model,
final SessionFeedbackQueryEnum query) {
switch (query) {
case SESSION:
mTitle.setText(model.getSessionTitle());
if (!TextUtils.isEmpty(model.getSessionSpeakers())) {
mSpeakers.setText(model.getSessionSpeakers());
} else {
mSpeakers.setVisibility(View.GONE);
}
AnalyticsHelper.sendScreenView("Feedback: " + model.getSessionTitle());
break;
}
}
https://github.com/google/iosched
java.lang.RuntimeException: Method setText in android.widget.TextView not mocked.
See http://g.co/androidstudio/not-mocked for details.
	 at android.widget.TextView.setText(TextView.java)
	 at lv.buzdin.alexey.MainActivityPresenterTest.test(MainActivityPresenterTest.java:39)
@Test
public void name() throws Exception {
TextView textView = new TextView(null);
textView.setText("hello");
}
android {
….
testOptions {
unitTests.returnDefaultValues = true
}
}
Toast.makeText(null, "", Toast.LENGTH_SHORT).show();
Toast.makeText(null, "", Toast.LENGTH_SHORT).show();
Unmockable*
Testable architecture
๏ Use MV* Patterns
๏ Dependency Injection is a must
๏ Try to use POJOs where possible
๏ Wrap static Android classes to Services
(Log, Toast, etc)
๏ Avoid highly coupling to android classes in *
code
Model - View - Whatever
(Activity/Fragment)
๏ Activity is polluted. (Lifecycle
Logic, LayoutInflater, static calls,
etc)
๏ We need a POJO
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
BaseApplication.inject(this);
setContentView(R.layout.activity_screen);
presenter.initPresenter(this);
presenter.initNavigationDrawer();
presenter.openScheduleScreen();
if (presenter.firstApplicationStart()) {
presenter.openNavigationDrawer();
}
}
public class MainActivityPresenter {
…
public void initPresenter(ActionBarActivity activity) {
this.activity = activity;
ButterKnife.inject(this, activity);
}
public void initNavigationDrawer() {
activity.setSupportActionBar(toolbar);
drawerToggle = new ActionBarDrawerToggle(activity, drawerLayout, R.string.app_name, R.string.app_name) {
@Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
listView.invalidateViews(); //Refresh counter for bookmarks
}
};
drawerToggle.setDrawerIndicatorEnabled(true);
drawerLayout.setDrawerListener(drawerToggle);
activity.getSupportActionBar().setDisplayHomeAsUpEnabled(true);
activity.getSupportActionBar().setHomeButtonEnabled(true);
listView.setAdapter(navigationAdapter);
}
}
Testable architecture
๏ Use MV* Patterns
๏ Dependency Injection is a must
๏ Try to use POJOs where possible
๏ Wrap static Android classes to Services
(Log, Toast, etc)
๏ Avoid highly coupling to android classes in *
code
Dagger 2
The fastest Java DI Framework!
https://google.github.io/dagger/
@Singleton
public class MainActivityPresenter {
@Inject SocialNetworkNavigationService socialsService;
@Inject SharedPrefsService preferences;
@Inject NavigationAdapter navigationAdapter;
…
public boolean firstApplicationStart() {
boolean subsequentStart = preferences.getBool(PreferencesConstants.SUBSEQUENT_START);
if (!subsequentStart) {
preferences.setBool(PreferencesConstants.SUBSEQUENT_START, true);
return true;
}
return false;
}
}
Testable architecture
๏ Use MV* Patterns
๏ Dependency Injection is a must
๏ Try to use POJOs where possible
๏ Wrap static Android classes to Services
(Log, Toast, etc)
๏ Avoid highly coupling to android classes in *
code
public class SharedPrefsService {
@Inject
public Context context;
private SharedPreferences getPrefs() {
return PreferenceManager.getDefaultSharedPreferences(context);
}
public boolean getBool(String key) {
return getPrefs().getBoolean(key, false);
}
public void setBool(String key, boolean value) {
getPrefs().edit().putBoolean(key, value).commit();
}
}
Testable architecture
๏ Use MV* Patterns
๏ Dependency Injection is a must
๏ Try to use POJOs where possible
๏ Wrap static Android classes to Services
(Log, Toast, etc)
๏ Avoid highly coupling to android classes in *
code
Removes View dependency for Whatever
Button b = (Button)findViewById(R.id.button);
b.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
b.setBackgroundColor(Red);
}
});
@InjectView(R.id.button)
Button b;
@OnClick(R.id.button)
public void onClick(View v) {
b.setBackgroundColor(Red);
}
Removes View dependency for Whatever
RxBus rxBus = new RxBus();
@InjectView(R.id.button) Button b;
Observable<Void> clicks = RxView.clicks(b);
public init() {
clicks.subscribe(aVoid -> { rxBus.send(new Click()); });
rxBus.toObserverable()
.filter(e -> e instanceof Click)
.subscribe(e -> {
b.setBackgroundColor(Red);
});
}
https://github.com/JakeWharton/RxBinding
Testable architecture with Rx
@Test
public void test() throws Exception {
MyFragment fragment = new MyFragment();
fragment.b = new Button(null) {
@Override
public void setBackgroundColor(int color) {
assertEquals(color, Red);
}
};
fragment.clicks = Observable.just(null);
fragment.init();
}
Mockito + PowerMock
Mocking, Spying
Object o = mock(Object.class);
doReturn(true).when(o).equals(any());
Object o = spy(“Hi”);
doReturn(true).when(o).equals(any());
o.hashCode() -> is real
@RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
@InjectMocks MyFragment fragment;
@Mock Button b;
@Test
public void test() throws Exception {
fragment.clicks = Observable.just(null);
fragment.init();
verify(b).setBackgroundColor(Red);
}
}
Toast.makeText(null, "", Toast.LENGTH_SHORT).show();
Unmockable*
Toast.makeText(null, "", Toast.LENGTH_SHORT).show();
Unmockable*
@RunWith(PowerMockRunner.class)
@PrepareForTest( { Toast.class })
public class PowerMockExample {
@Test
public void testPowerMock() throws Exception {
Toast mock = mock(Toast.class);
mockStatic(Toast.class);
when(Toast.makeText(any(), anyString(), anyInt())).thenReturn(mock);
Toast.makeText(null, "1", Toast.LENGTH_SHORT).show();
}
}
JUnit Extra Features
Helpful for Android Developers
JUnit Lifecycle
public class RunnerTest {
@BeforeClass public static void beforeClass() { out.println("Before Class");}
@Before public void before() { out.println("Before");}
@Test public void test() { out.println("Test"); }
@After public void after() { out.println("After"); }
@AfterClass public static void afterClass() { out.println("After Class"); }
}
JUnit Lifecycle
public class RunnerTest {
@BeforeClass public static void beforeClass() { out.println("Before Class");}
@Before public void before() { out.println("Before");}
@Test public void test() { out.println("Test"); }
@After public void after() { out.println("After"); }
@AfterClass public static void afterClass() { out.println("After Class"); }
}
Before Class
Before
Test
After
After Class
Process finished with exit code 0
Custom Runner:
BlockJUnit4ClassRunner
or Runner
public class CustomRunner extends BlockJUnit4ClassRunner{
public static void runnerBefore() { System.out.println("Runner Before");}
public static void runnerBeforeClass() { System.out.println("Runner Before Class"); }
public static void runnerAfter() { System.out.println("Runner After");}
public static void runnerAfterClass() { System.out.println("Runner After Class"); }
@Override protected Statement withBefores(FrameworkMethod method, Object t, Statement st) {
List<FrameworkMethod> list = getFrameworkMethods("runnerBefore");
return new RunBefores(super.withBefores(method, t, st), list, t);
}
….
private List<FrameworkMethod> getFrameworkMethods(String methodName) {
try {
Method runnerBefore = getClass().getDeclaredMethod(methodName);
return Collections.singletonList(new FrameworkMethod(runnerBefore));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@RunWith(CustomRunner.class)
public class RunnerTest {
….
}
Runner Before Class
Before Class
Runner Before
Before
Test
After
Runner After
After Class
Runner After Class
Process finished with exit code 0
@RunWith(CustomRunner.class)
public class RunnerTest {
….
}
Runner Before Class
Before Class
Runner Before
Before
Test
After
Runner After
After Class
Runner After Class
Process finished with exit code 0
AndroidJUnitRunner +
MockitoJUnitRunner +
Parametrized
JUnit Rules
•Rules allow flexible addition of the behaviour
of each test method in a test class
•Base Rules Provided in JUnit:
Temporary Folder Rule; ExternalResource Rule;
ErrorCollector Rule; TestName Rule; Timeout Rule;
RuleChain
public class CustomRule implements TestRule {
private boolean classRule;
public CustomRule(boolean classRule) { this.classRule = classRule; }
@Override
public Statement apply(Statement base, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
System.out.println(classRule ? "Class Rule Before" : "Rule Before");
try { base.evaluate();
} finally { System.out.println(classRule ? "Class Rule After" : "Rule After”); }
}
};
}
}
@RunWith(CustomRunner.class)
public class RunnerTest {
@ClassRule public static CustomRule classRule = new CustomRule(true);
@Rule public CustomRule rule = new CustomRule(false);
@BeforeClass public static void beforeClass() { out.println("Before Class");}
@Before public void before() { out.println("Before");}
@Test public void test() { out.println("Test"); }
@After public void after() { out.println("After"); }
@AfterClass public static void afterClass() { out.println("After Class"); }
}
Class Rule Before
Runner Before Class
Before Class
Rule Before
Runner Before
Before
Test
After
Runner After
Rule After
After Class
Runner After Class
Class Rule After
Class Rule Before
Runner Before Class
Before Class
Rule Before
Runner Before
Before
Test
After
Runner After
Rule After
After Class
Runner After Class
Class Rule After
public static class UseRuleChain {
@Rule
public RuleChain chain= RuleChain
.outerRule(new LoggingRule("outer rule")
.around(new LoggingRule("middle rule")
.around(new LoggingRule("inner rule");
@Test
public void example() {
assertTrue(true);
}
}
starting outer rule
starting middle rule
starting inner rule
finished inner rule
finished middle rule
finished outer rule
Rules > Runners
Test Specification
1. Preparation
2. Testable Action
3. Assertion
Test Specification
1. Preparation
2. Testable Action
3. Assertion
https://github.com/hamcrest/JavaHamcrest
assertThat(T object, Matcher<T> matcher)
@Test
public void testValidIPAddress() throws InvalidIPAddressException
{
IPAddress addr = new IPAddress("127.0.0.1");
byte[] octets = addr.getOctets();
assertTrue(octets[0] == 127);
assertTrue(octets[1] == 0);
assertTrue(octets[2] == 0);
assertTrue(octets[3] == 1);
}
Bad Test
Examples
•assertThat(2, is(2))
•assertThat(“s”, is(nullValue()))
•assertThat(“s”, is(new String(“s”)))
•assertThat(“s”, equalTo(new String(“s”)))
•assertThat(“s”, not(equalTo(“d”)))
•assertThat(“s”, instanceOf(String.class))
http://hamcrest.org/JavaHamcrest/javadoc/1.3/
List matcher
•assertThat(ids, hasItem(10))
•assertThat(ids, contains(5, 8))
•assertThat(ids, containsInAnyOrder(5, 8))
•assertThat(ids, everyItem(greaterThan(3)))
AllOf AnyOf
assertThat(name, anyOf(startsWith(“A”), endsWith(“B”)))
assertThat(ids, allOf(
	 	 hasSize(5),
	 	 hasItem(10),
	 	 everyItem(greaterThan(3))
))
Error messages
assertThat("s", is(nullValue()))
assertThat(true, is(false))
Error messages
assertThat(1, is(allOf(not(1), not(2), not(10))))
Custom matchers
private Matcher<Foo> hasNumber(final int i) {
return new TypeSafeMatcher<Foo>() {
@Override public void describeTo(final Description description) {
description.appendText("getNumber should return ").appendValue(i);
}
@Override protected void describeMismatchSafely(final Foo item, final
Description mismatchDescription) {
mismatchDescription.appendText(" was ").appendValue(item.getNumber());
}
@Override protected boolean matchesSafely(final Foo item) {
return i == item.getNumber();
}
};
}
hamcrest-rx
Matcher<TestSubscriber<T>> hasValues(final Matcher<? super List<T>> eventsMatcher)
Matcher<TestSubscriber<T>> hasOnlyValues(final Matcher<? super List<T>> values)
Matcher<TestSubscriber<T>> hasOnlyValue(final Matcher<? super T> valueMatcher)
Matcher<TestSubscriber<T>> hasNoValues()
Matcher<TestSubscriber<T>> hasErrors(final Matcher<? super List<Throwable>> err)
Matcher<TestSubscriber<T>> hasNoErrors()
Matcher<TestSubscriber<T>> hasOnlyErrors(final Matcher<? super List<Throwable>> err)
https://github.com/zalando-incubator/undertaking/blob/master/src/test/java/org/
zalando/undertaking/test/rx/hamcrest/TestSubscriberMatchers.java
https://github.com/hertzsprung/hamcrest-json
assertThat(
"{"age":43, "friend_ids":[16, 52, 23]}",
sameJSONAs("{"friend_ids":[52, 23, 16]}")
.allowingExtraUnexpectedFields()
.allowingAnyArrayOrdering());
hamcrest-json
Parameterised tests
Parameterised with Name
Square Burst
https://github.com/square/burst
public enum Soda { PEPSI, COKE }
public enum Sets {
HASH_SET() {
@Override public <T> Set<T> create() {
return new HashSet<T>();
}
},
LINKED_HASH_SET() { … },
TREE_SET() { … }
public abstract <T> Set<T> create();
}
https://github.com/square/burst
@RunWith(BurstJUnit4.class)
public class DrinkSodaTest {
@Burst Soda soda;
@Burst Sets sets;
@Test public void drinkFavoriteSodas(Soda soda) {
// TODO Test drink method with 'soda'...
}
}
Square Burst
https://github.com/square/burst
@RunWith(BurstJUnit4.class)
public class DrinkSodaTest {
private final Set<Soda> favorites;
public DrinkSodaTest(Sets sets) {
favorites = sets.create();
}
@Test public void trackFavorites() { // TODO … }
@Test public void drinkFavoriteSodas(Soda soda) { //TODO … }
}
Square Burst
JUnitParams
https://github.com/Pragmatists/JUnitParams
@RunWith(JUnitParamsRunner.class)
public class PersonTest {
@Test
@Parameters({"17, false”, "22, true" })
public void personIsAdult(int age, boolean valid) throws Exception {
assertThat(new Person(age).isAdult(), is(valid));
}
}
Enclosed
Provides a way to use multiple JUnit Runners in a test class
https://www.indiegogo.com/projects/junit-lambda
http://junit.org/junit5/
JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
class FirstJUnit5Tests {
@Test
void myFirstTest() {
assertEquals(2, 1 + 1);
}
}
JUnit 5 Features
Grouped Assertions
@Test
void groupedAssertions() {
// In a grouped assertion all assertions are executed, and any
// failures will be reported together.
assertAll("address",
() -> assertEquals("John", address.getFirstName()),
() -> assertEquals("User", address.getLastName())
);
}
Throwable Assertions
@Test
void exceptionTesting() {
Throwable exception = assertThrows(IllegalArgumentException.class, () -> {
throw new IllegalArgumentException("a message");
});
assertEquals("a message", exception.getMessage());
}
No assertThat()
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import org.junit.jupiter.api.Test;
class HamcrestAssertionDemo {
@Test
void assertWithHamcrestMatcher() {
assertThat(2 + 1, is(equalTo(3)));
}
}
No Runners or Rules > Extensions
@ExtendWith(MockitoExtension.class)
class MyMockitoTest {
@BeforeEach
void init(@Mock Person person) {
when(person.getName()).thenReturn("Dilbert");
}
@Test
void simpleTestWithInjectedMock(@Mock Person person) {
assertEquals("Dilbert", person.getName());
}
}
Dynamic Tests
class DynamicTestsDemo {
@TestFactory
Collection<DynamicTest> dynamicTestsFromCollection() {
return Arrays.asList(
dynamicTest("1st dynamic test", () -> assertTrue(true)),
dynamicTest("2nd dynamic test", () -> assertEquals(4, 2 * 2))
);
}
}
Collection, Iterable, Iterator, Stream
in Android
• Not coming soon
• Would require a rewrite for all testing libraries
• Would require Android Studio support
• Would simplify the Extension model
https://github.com/junit-team/junit5/issues/204
Integration Tests
๏ Uses Robolectric framework
๏ Runs on JVM with Shadow Android SDK
๏ Has access to Context and all Android
peripheral
Robolectric
@RunWith(RobolectricTestRunner.class)
public class MyActivityTest {
@Test
public void clickingButton_shouldChangeResultsViewText() throws Exception {
MyActivity activity = Robolectric.setupActivity(MyActivity.class);
Button button = (Button) activity.findViewById(R.id.button);
TextView results = (TextView) activity.findViewById(R.id.results);
button.performClick();
assertThat(results.getText().toString()).isEqualTo("Robolectric Rocks!");
}
}
ActivityController controller = Robolectric.buildActivity(MyAwesomeActivity.class).create().start();
Activity activity = controller.get();
// assert that something hasn't happened
activityController.resume();
// assert it happened!
Activity activity = Robolectric.buildActivity(MyAwesomeActivity.class)
.create().start().resume().visible().get();
Activity Lifecycle
public class SharedPrefsService {
@Inject
public Context context;
private SharedPreferences getPrefs() {
return PreferenceManager.getDefaultSharedPreferences(context);
}
public boolean getBool(String key) {
return getPrefs().getBoolean(key, false);
}
public void setBool(String key, boolean value) {
getPrefs().edit().putBoolean(key, value).commit();
}
}
Robolectric
๏ Life saver when complex Android SDK
calls should be tested
๏ Slow compared to Unit Tests
๏ Not up to date to the latest SDKs
(API 24 not supported yet)
UI Tests
๏ Runs on actual Android Device
๏ Slower the Unit tests
๏ Brittle and dependant on
device health
public void testRecorded() throws Exception {
if (solo.waitForText("Hello!")) {
solo.clickOnView(solo.findViewById("R.id.sign_in"));
solo.enterText((EditText) solo.findViewById("R.id.login_username"),"username");
solo.enterText((EditText) solo.findViewById("R.id.login_password"),"password");
solo.clickOnView(solo.findViewById("R.id.login_login"));
solo.waitForActivity("HomeTabActivity");
} solo.clickOnView(solo.findViewById("R.id.menu_compose_tweet") );
solo.enterText((EditText) solo.findViewById(“R.id.edit"), "Testdroid");
solo.clickOnView(solo.findViewById("R.id.composer_post"));
}
Robotium
Android Espresso
@Test

public void multiActivityTest() {

onView(withId(R.id.date))

.perform(click());

// Loads another activity riiiight here

onView(allOf(withId(R.id.date_expanded), withText("SomeRandomDate")))

.check(matches(isDisplayed()))

.perform(click());

// Yay! No waiting!

}
Espresso comes with Hamcrest integration
@Test

public void dateTest() {

onView(withId(R.id.date))

.check(matches(withText("2014-10-15")));

}
Robotium vs Espresso
• Espresso faster
• Robotium has bigger SDK coverage
• Espresso has built in wait mechanism that is
optimised for android lifecycle
http://www.stevenmarkford.com/android-espresso-vs-robotium-
benchmarks/
Looking into Cross-platform UI Test
Automation?
https://www.youtube.com/watch?v=iwvueGzwVyk
Cross platform tests
If you have dedicated QA team and product on multiple
platforms - go Calabash or Appium
• More flacky tests
• Less performant speed
• Some test reuse
• Easier for QA
BFF
BFF
DB
DB
DB
AMQP
How to run UI test
• Don’t initialize run-time dependencies (event
tracking, analytics, long-init things like payment
solutions)
• Don’t hit up real backend, mock out responses
• Insert appropriate test data before test starts
running
How to mock a Server
- Mock Server through DI
- Mock HTTP Server instance on Device
- Dev instance of Server
DI: Create a custom Test Runner
public class MockTestRunner extends AndroidJUnitRunner {

@Override

public Application newApplication(ClassLoader cl, String className, Context ctx)

throws InstantiationException, IllegalAccessException, ClassNotFoundException {

return super.newApplication(cl, MockDemoApplication.class.getName(), ctx);

}

}
DI: Create a custom Test Application
public class MockDemoApplication extends DemoApplication {

@Override

protected DemoComponent createComponent() {

return DaggerMainActivityTest_TestComponent.builder().build();

}

}
MockServer on Device: AndroidAsync
https://github.com/koush/AndroidAsync
AsyncHttpServer server = new AsyncHttpServer();
server.get("/", new HttpServerRequestCallback() {
@Override
public void onRequest(AsyncHttpServerRequest request,
AsyncHttpServerResponse response) {
response.send("Hello!!!");
}
});
server.listen(5000);
How to run UI tests on CI?
Android Jenkins Plugin
https://wiki.jenkins-ci.org/display/JENKINS/Android+Emulator+Plugin
Multi-configuration (matrix) job
Android Jenkins Plugin
https://github.com/Genymobile/genymotion-gradle-plugin
1. genymotion {
2. devices {
3. nexus5 {
4. template "Google Nexus 5 - 4.4.4 - API 19 - 1080x1920"
5. }
6. }
7. }
https://medium.com/@Genymotion/android-os-now-available-as-an-amazon-
machine-image-72748130436b#.njabkxnih
https://github.com/square/spoon
https://github.com/stanfy/spoon-gradle-plugin
http://openstf.io/
Conclusion
๏ Unit tests are cheap, make them your first
frontier
๏ Adapt code to make it more testable
๏ Structure tests with @Rules and Hamcrest
Matchers
๏ Mockito + Powermock will help to mock
Android else Robolectric will
Conclusion
๏ UI tests are harder to write and maintain
๏ If you have a dedicated mobile QA team
think of cross-platform tests
๏ For UI tests have a config for Mocked server
and other integration points
๏ Configure either emulator startup or device
farm on your CI
TESTS ARE MADE
TO MAKEYOU FEEL SECURE!
LIKE A LOVELY HUG ♥
Q&A
Thank You!
@AlexeyBuzdinFollow me at

More Related Content

What's hot

The Ring programming language version 1.8 book - Part 77 of 202
The Ring programming language version 1.8 book - Part 77 of 202The Ring programming language version 1.8 book - Part 77 of 202
The Ring programming language version 1.8 book - Part 77 of 202
Mahmoud Samir Fayed
 
The Ring programming language version 1.2 book - Part 51 of 84
The Ring programming language version 1.2 book - Part 51 of 84The Ring programming language version 1.2 book - Part 51 of 84
The Ring programming language version 1.2 book - Part 51 of 84
Mahmoud Samir Fayed
 
The Ring programming language version 1.7 book - Part 75 of 196
The Ring programming language version 1.7 book - Part 75 of 196The Ring programming language version 1.7 book - Part 75 of 196
The Ring programming language version 1.7 book - Part 75 of 196
Mahmoud Samir Fayed
 
Visual Component Testing -- w/ Gil Tayar (Applitools) and Gleb Bahmutov (Cyp...
Visual Component Testing  -- w/ Gil Tayar (Applitools) and Gleb Bahmutov (Cyp...Visual Component Testing  -- w/ Gil Tayar (Applitools) and Gleb Bahmutov (Cyp...
Visual Component Testing -- w/ Gil Tayar (Applitools) and Gleb Bahmutov (Cyp...
Applitools
 
Androidaop 170105090257
Androidaop 170105090257Androidaop 170105090257
Androidaop 170105090257
newegg
 
Migrating from Struts 1 to Struts 2
Migrating from Struts 1 to Struts 2Migrating from Struts 1 to Struts 2
Migrating from Struts 1 to Struts 2
Matt Raible
 
Android Loaders : Reloaded
Android Loaders : ReloadedAndroid Loaders : Reloaded
Android Loaders : Reloaded
cbeyls
 
Spock
SpockSpock
Web components with java by Haijian Wang
Web components with java by Haijian WangWeb components with java by Haijian Wang
Web components with java by Haijian Wang
GWTcon
 
Code to DI For - Dependency Injection for Modern Applications
Code to DI For - Dependency Injection for Modern ApplicationsCode to DI For - Dependency Injection for Modern Applications
Code to DI For - Dependency Injection for Modern Applications
Caleb Jenkins
 
The Ring programming language version 1.5.2 book - Part 68 of 181
The Ring programming language version 1.5.2 book - Part 68 of 181The Ring programming language version 1.5.2 book - Part 68 of 181
The Ring programming language version 1.5.2 book - Part 68 of 181
Mahmoud Samir Fayed
 
Open sourcing the store
Open sourcing the storeOpen sourcing the store
Open sourcing the store
Mike Nakhimovich
 
Droidcon2013 pro guard, optimizer and obfuscator in the android sdk_eric lafo...
Droidcon2013 pro guard, optimizer and obfuscator in the android sdk_eric lafo...Droidcon2013 pro guard, optimizer and obfuscator in the android sdk_eric lafo...
Droidcon2013 pro guard, optimizer and obfuscator in the android sdk_eric lafo...
Droidcon Berlin
 
Learning Java 4 – Swing, SQL, and Security API
Learning Java 4 – Swing, SQL, and Security APILearning Java 4 – Swing, SQL, and Security API
Learning Java 4 – Swing, SQL, and Security API
caswenson
 
SolrJ: Power and Pitfalls - Jason Gerlowski, Lucidworks
SolrJ: Power and Pitfalls - Jason Gerlowski, LucidworksSolrJ: Power and Pitfalls - Jason Gerlowski, Lucidworks
SolrJ: Power and Pitfalls - Jason Gerlowski, Lucidworks
Lucidworks
 
What is the difference between struts 1 vs struts 2
What is the difference between struts 1 vs struts 2What is the difference between struts 1 vs struts 2
What is the difference between struts 1 vs struts 2
Santosh Singh Paliwal
 
Modern Android Architecture
Modern Android ArchitectureModern Android Architecture
Modern Android Architecture
Eric Maxwell
 
Capture image on eye blink
Capture image on eye blinkCapture image on eye blink
Capture image on eye blink
InnovationM
 
Android Unit Testing With Robolectric
Android Unit Testing With RobolectricAndroid Unit Testing With Robolectric
Android Unit Testing With Robolectric
Danny Preussler
 

What's hot (19)

The Ring programming language version 1.8 book - Part 77 of 202
The Ring programming language version 1.8 book - Part 77 of 202The Ring programming language version 1.8 book - Part 77 of 202
The Ring programming language version 1.8 book - Part 77 of 202
 
The Ring programming language version 1.2 book - Part 51 of 84
The Ring programming language version 1.2 book - Part 51 of 84The Ring programming language version 1.2 book - Part 51 of 84
The Ring programming language version 1.2 book - Part 51 of 84
 
The Ring programming language version 1.7 book - Part 75 of 196
The Ring programming language version 1.7 book - Part 75 of 196The Ring programming language version 1.7 book - Part 75 of 196
The Ring programming language version 1.7 book - Part 75 of 196
 
Visual Component Testing -- w/ Gil Tayar (Applitools) and Gleb Bahmutov (Cyp...
Visual Component Testing  -- w/ Gil Tayar (Applitools) and Gleb Bahmutov (Cyp...Visual Component Testing  -- w/ Gil Tayar (Applitools) and Gleb Bahmutov (Cyp...
Visual Component Testing -- w/ Gil Tayar (Applitools) and Gleb Bahmutov (Cyp...
 
Androidaop 170105090257
Androidaop 170105090257Androidaop 170105090257
Androidaop 170105090257
 
Migrating from Struts 1 to Struts 2
Migrating from Struts 1 to Struts 2Migrating from Struts 1 to Struts 2
Migrating from Struts 1 to Struts 2
 
Android Loaders : Reloaded
Android Loaders : ReloadedAndroid Loaders : Reloaded
Android Loaders : Reloaded
 
Spock
SpockSpock
Spock
 
Web components with java by Haijian Wang
Web components with java by Haijian WangWeb components with java by Haijian Wang
Web components with java by Haijian Wang
 
Code to DI For - Dependency Injection for Modern Applications
Code to DI For - Dependency Injection for Modern ApplicationsCode to DI For - Dependency Injection for Modern Applications
Code to DI For - Dependency Injection for Modern Applications
 
The Ring programming language version 1.5.2 book - Part 68 of 181
The Ring programming language version 1.5.2 book - Part 68 of 181The Ring programming language version 1.5.2 book - Part 68 of 181
The Ring programming language version 1.5.2 book - Part 68 of 181
 
Open sourcing the store
Open sourcing the storeOpen sourcing the store
Open sourcing the store
 
Droidcon2013 pro guard, optimizer and obfuscator in the android sdk_eric lafo...
Droidcon2013 pro guard, optimizer and obfuscator in the android sdk_eric lafo...Droidcon2013 pro guard, optimizer and obfuscator in the android sdk_eric lafo...
Droidcon2013 pro guard, optimizer and obfuscator in the android sdk_eric lafo...
 
Learning Java 4 – Swing, SQL, and Security API
Learning Java 4 – Swing, SQL, and Security APILearning Java 4 – Swing, SQL, and Security API
Learning Java 4 – Swing, SQL, and Security API
 
SolrJ: Power and Pitfalls - Jason Gerlowski, Lucidworks
SolrJ: Power and Pitfalls - Jason Gerlowski, LucidworksSolrJ: Power and Pitfalls - Jason Gerlowski, Lucidworks
SolrJ: Power and Pitfalls - Jason Gerlowski, Lucidworks
 
What is the difference between struts 1 vs struts 2
What is the difference between struts 1 vs struts 2What is the difference between struts 1 vs struts 2
What is the difference between struts 1 vs struts 2
 
Modern Android Architecture
Modern Android ArchitectureModern Android Architecture
Modern Android Architecture
 
Capture image on eye blink
Capture image on eye blinkCapture image on eye blink
Capture image on eye blink
 
Android Unit Testing With Robolectric
Android Unit Testing With RobolectricAndroid Unit Testing With Robolectric
Android Unit Testing With Robolectric
 

Similar to Alexey Buzdin "Maslow's Pyramid of Android Testing"

比XML更好用的Java Annotation
比XML更好用的Java Annotation比XML更好用的Java Annotation
比XML更好用的Java Annotation
javatwo2011
 
Android testing
Android testingAndroid testing
Android testing
Sean Tsai
 
An Introduction To Unit Testing and TDD
An Introduction To Unit Testing and TDDAn Introduction To Unit Testing and TDD
An Introduction To Unit Testing and TDD
Ahmed Ehab AbdulAziz
 
Thomas braun dependency-injection_with_robo_guice-presentation-final
Thomas braun dependency-injection_with_robo_guice-presentation-finalThomas braun dependency-injection_with_robo_guice-presentation-final
Thomas braun dependency-injection_with_robo_guice-presentation-final
Droidcon Berlin
 
Testing basics for developers
Testing basics for developersTesting basics for developers
Testing basics for developers
Anton Udovychenko
 
Guide to the jungle of testing frameworks
Guide to the jungle of testing frameworksGuide to the jungle of testing frameworks
Guide to the jungle of testing frameworks
Tomáš Kypta
 
Unit Testing on Android - Droidcon Berlin 2015
Unit Testing on Android - Droidcon Berlin 2015Unit Testing on Android - Droidcon Berlin 2015
Unit Testing on Android - Droidcon Berlin 2015
Buşra Deniz, CSM
 
Android Architecture Components
Android Architecture ComponentsAndroid Architecture Components
Android Architecture Components
BurhanuddinRashid
 
Unit & Automation Testing in Android - Stanislav Gatsev, Melon
Unit & Automation Testing in Android - Stanislav Gatsev, MelonUnit & Automation Testing in Android - Stanislav Gatsev, Melon
Unit & Automation Testing in Android - Stanislav Gatsev, Melon
beITconference
 
SWTBot Tutorial
SWTBot TutorialSWTBot Tutorial
SWTBot Tutorial
Chris Aniszczyk
 
JSUG - Google Guice by Jan Zarnikov
JSUG - Google Guice by Jan ZarnikovJSUG - Google Guice by Jan Zarnikov
JSUG - Google Guice by Jan Zarnikov
Christoph Pickl
 
OpenWebBeans and DeltaSpike at ApacheCon
OpenWebBeans and DeltaSpike at ApacheConOpenWebBeans and DeltaSpike at ApacheCon
OpenWebBeans and DeltaSpike at ApacheCon
os890
 
So how do I test my Sling application?
 So how do I test my Sling application? So how do I test my Sling application?
So how do I test my Sling application?
Robert Munteanu
 
JUnit5 and TestContainers
JUnit5 and TestContainersJUnit5 and TestContainers
JUnit5 and TestContainers
Sunghyouk Bae
 
E:\Plp 2009 2\Plp 9
E:\Plp 2009 2\Plp 9E:\Plp 2009 2\Plp 9
E:\Plp 2009 2\Plp 9
Ismar Silveira
 
Paradigmas de linguagens de programacao - aula#9
Paradigmas de linguagens de programacao - aula#9Paradigmas de linguagens de programacao - aula#9
Paradigmas de linguagens de programacao - aula#9
Ismar Silveira
 
Android Building, Testing and reversing
Android Building, Testing and reversingAndroid Building, Testing and reversing
Android Building, Testing and reversing
Enrique López Mañas
 
Junit and testNG
Junit and testNGJunit and testNG
Junit and testNG
Марія Русин
 
Robotium Tutorial
Robotium TutorialRobotium Tutorial
Robotium Tutorial
Mobile March
 
Spring Boot
Spring BootSpring Boot
Spring Boot
Jiayun Zhou
 

Similar to Alexey Buzdin "Maslow's Pyramid of Android Testing" (20)

比XML更好用的Java Annotation
比XML更好用的Java Annotation比XML更好用的Java Annotation
比XML更好用的Java Annotation
 
Android testing
Android testingAndroid testing
Android testing
 
An Introduction To Unit Testing and TDD
An Introduction To Unit Testing and TDDAn Introduction To Unit Testing and TDD
An Introduction To Unit Testing and TDD
 
Thomas braun dependency-injection_with_robo_guice-presentation-final
Thomas braun dependency-injection_with_robo_guice-presentation-finalThomas braun dependency-injection_with_robo_guice-presentation-final
Thomas braun dependency-injection_with_robo_guice-presentation-final
 
Testing basics for developers
Testing basics for developersTesting basics for developers
Testing basics for developers
 
Guide to the jungle of testing frameworks
Guide to the jungle of testing frameworksGuide to the jungle of testing frameworks
Guide to the jungle of testing frameworks
 
Unit Testing on Android - Droidcon Berlin 2015
Unit Testing on Android - Droidcon Berlin 2015Unit Testing on Android - Droidcon Berlin 2015
Unit Testing on Android - Droidcon Berlin 2015
 
Android Architecture Components
Android Architecture ComponentsAndroid Architecture Components
Android Architecture Components
 
Unit & Automation Testing in Android - Stanislav Gatsev, Melon
Unit & Automation Testing in Android - Stanislav Gatsev, MelonUnit & Automation Testing in Android - Stanislav Gatsev, Melon
Unit & Automation Testing in Android - Stanislav Gatsev, Melon
 
SWTBot Tutorial
SWTBot TutorialSWTBot Tutorial
SWTBot Tutorial
 
JSUG - Google Guice by Jan Zarnikov
JSUG - Google Guice by Jan ZarnikovJSUG - Google Guice by Jan Zarnikov
JSUG - Google Guice by Jan Zarnikov
 
OpenWebBeans and DeltaSpike at ApacheCon
OpenWebBeans and DeltaSpike at ApacheConOpenWebBeans and DeltaSpike at ApacheCon
OpenWebBeans and DeltaSpike at ApacheCon
 
So how do I test my Sling application?
 So how do I test my Sling application? So how do I test my Sling application?
So how do I test my Sling application?
 
JUnit5 and TestContainers
JUnit5 and TestContainersJUnit5 and TestContainers
JUnit5 and TestContainers
 
E:\Plp 2009 2\Plp 9
E:\Plp 2009 2\Plp 9E:\Plp 2009 2\Plp 9
E:\Plp 2009 2\Plp 9
 
Paradigmas de linguagens de programacao - aula#9
Paradigmas de linguagens de programacao - aula#9Paradigmas de linguagens de programacao - aula#9
Paradigmas de linguagens de programacao - aula#9
 
Android Building, Testing and reversing
Android Building, Testing and reversingAndroid Building, Testing and reversing
Android Building, Testing and reversing
 
Junit and testNG
Junit and testNGJunit and testNG
Junit and testNG
 
Robotium Tutorial
Robotium TutorialRobotium Tutorial
Robotium Tutorial
 
Spring Boot
Spring BootSpring Boot
Spring Boot
 

More from IT Event

Denis Radin - "Applying NASA coding guidelines to JavaScript or airspace is c...
Denis Radin - "Applying NASA coding guidelines to JavaScript or airspace is c...Denis Radin - "Applying NASA coding guidelines to JavaScript or airspace is c...
Denis Radin - "Applying NASA coding guidelines to JavaScript or airspace is c...
IT Event
 
Sara Harkousse - "Web Components: It's all rainbows and unicorns! Is it?"
Sara Harkousse - "Web Components: It's all rainbows and unicorns! Is it?"Sara Harkousse - "Web Components: It's all rainbows and unicorns! Is it?"
Sara Harkousse - "Web Components: It's all rainbows and unicorns! Is it?"
IT Event
 
Max Voloshin - "Organization of frontend development for products with micros...
Max Voloshin - "Organization of frontend development for products with micros...Max Voloshin - "Organization of frontend development for products with micros...
Max Voloshin - "Organization of frontend development for products with micros...
IT Event
 
Roman Romanovsky, Sergey Rak - "JavaScript в IoT "
Roman Romanovsky, Sergey Rak - "JavaScript в IoT "Roman Romanovsky, Sergey Rak - "JavaScript в IoT "
Roman Romanovsky, Sergey Rak - "JavaScript в IoT "
IT Event
 
Konstantin Krivlenia - "Continuous integration for frontend"
Konstantin Krivlenia - "Continuous integration for frontend"Konstantin Krivlenia - "Continuous integration for frontend"
Konstantin Krivlenia - "Continuous integration for frontend"
IT Event
 
Illya Klymov - "Vue.JS: What did I swap React for in 2017 and why?"
Illya Klymov - "Vue.JS: What did I swap React for in 2017 and why?"Illya Klymov - "Vue.JS: What did I swap React for in 2017 and why?"
Illya Klymov - "Vue.JS: What did I swap React for in 2017 and why?"
IT Event
 
Evgeny Gusev - "A circular firing squad: How technologies drag frontend down"
Evgeny Gusev - "A circular firing squad: How technologies drag frontend down"Evgeny Gusev - "A circular firing squad: How technologies drag frontend down"
Evgeny Gusev - "A circular firing squad: How technologies drag frontend down"
IT Event
 
Vladimir Grinenko - "Dependencies in component web done right"
Vladimir Grinenko - "Dependencies in component web done right"Vladimir Grinenko - "Dependencies in component web done right"
Vladimir Grinenko - "Dependencies in component web done right"
IT Event
 
Dmitry Bartalevich - "How to train your WebVR"
Dmitry Bartalevich - "How to train your WebVR"Dmitry Bartalevich - "How to train your WebVR"
Dmitry Bartalevich - "How to train your WebVR"
IT Event
 
Aleksey Bogachuk - "Offline Second"
Aleksey Bogachuk - "Offline Second"Aleksey Bogachuk - "Offline Second"
Aleksey Bogachuk - "Offline Second"
IT Event
 
James Allardice - "Building a better login with the credential management API"
James Allardice - "Building a better login with the credential management API"James Allardice - "Building a better login with the credential management API"
James Allardice - "Building a better login with the credential management API"
IT Event
 
Fedor Skuratov "Dark Social: as messengers change the market of social media ...
Fedor Skuratov "Dark Social: as messengers change the market of social media ...Fedor Skuratov "Dark Social: as messengers change the market of social media ...
Fedor Skuratov "Dark Social: as messengers change the market of social media ...
IT Event
 
Андрей Зайчиков "Архитектура распределенных кластеров NoSQL на AWS"
Андрей Зайчиков "Архитектура распределенных кластеров NoSQL на AWS"Андрей Зайчиков "Архитектура распределенных кластеров NoSQL на AWS"
Андрей Зайчиков "Архитектура распределенных кластеров NoSQL на AWS"
IT Event
 
Алексей Рагозин "Java и linux борьба за микросекунды"
Алексей Рагозин "Java и linux борьба за микросекунды"Алексей Рагозин "Java и linux борьба за микросекунды"
Алексей Рагозин "Java и linux борьба за микросекунды"
IT Event
 
Volodymyr Lyubinets "Introduction to big data processing with Apache Spark"
Volodymyr Lyubinets "Introduction to big data processing with Apache Spark"Volodymyr Lyubinets "Introduction to big data processing with Apache Spark"
Volodymyr Lyubinets "Introduction to big data processing with Apache Spark"
IT Event
 
Наш ответ Uber’у
Наш ответ Uber’уНаш ответ Uber’у
Наш ответ Uber’у
IT Event
 
Александр Крашенинников "Hadoop High Availability: опыт Badoo"
Александр Крашенинников "Hadoop High Availability: опыт Badoo"Александр Крашенинников "Hadoop High Availability: опыт Badoo"
Александр Крашенинников "Hadoop High Availability: опыт Badoo"
IT Event
 
Leonid Vasilyev "Building, deploying and running production code at Dropbox"
Leonid Vasilyev  "Building, deploying and running production code at Dropbox"Leonid Vasilyev  "Building, deploying and running production code at Dropbox"
Leonid Vasilyev "Building, deploying and running production code at Dropbox"
IT Event
 
Анатолий Пласковский "Миллионы карточных платежей за месяц, или как потерять ...
Анатолий Пласковский "Миллионы карточных платежей за месяц, или как потерять ...Анатолий Пласковский "Миллионы карточных платежей за месяц, или как потерять ...
Анатолий Пласковский "Миллионы карточных платежей за месяц, или как потерять ...
IT Event
 
Mete Atamel "Resilient microservices with kubernetes"
Mete Atamel "Resilient microservices with kubernetes"Mete Atamel "Resilient microservices with kubernetes"
Mete Atamel "Resilient microservices with kubernetes"
IT Event
 

More from IT Event (20)

Denis Radin - "Applying NASA coding guidelines to JavaScript or airspace is c...
Denis Radin - "Applying NASA coding guidelines to JavaScript or airspace is c...Denis Radin - "Applying NASA coding guidelines to JavaScript or airspace is c...
Denis Radin - "Applying NASA coding guidelines to JavaScript or airspace is c...
 
Sara Harkousse - "Web Components: It's all rainbows and unicorns! Is it?"
Sara Harkousse - "Web Components: It's all rainbows and unicorns! Is it?"Sara Harkousse - "Web Components: It's all rainbows and unicorns! Is it?"
Sara Harkousse - "Web Components: It's all rainbows and unicorns! Is it?"
 
Max Voloshin - "Organization of frontend development for products with micros...
Max Voloshin - "Organization of frontend development for products with micros...Max Voloshin - "Organization of frontend development for products with micros...
Max Voloshin - "Organization of frontend development for products with micros...
 
Roman Romanovsky, Sergey Rak - "JavaScript в IoT "
Roman Romanovsky, Sergey Rak - "JavaScript в IoT "Roman Romanovsky, Sergey Rak - "JavaScript в IoT "
Roman Romanovsky, Sergey Rak - "JavaScript в IoT "
 
Konstantin Krivlenia - "Continuous integration for frontend"
Konstantin Krivlenia - "Continuous integration for frontend"Konstantin Krivlenia - "Continuous integration for frontend"
Konstantin Krivlenia - "Continuous integration for frontend"
 
Illya Klymov - "Vue.JS: What did I swap React for in 2017 and why?"
Illya Klymov - "Vue.JS: What did I swap React for in 2017 and why?"Illya Klymov - "Vue.JS: What did I swap React for in 2017 and why?"
Illya Klymov - "Vue.JS: What did I swap React for in 2017 and why?"
 
Evgeny Gusev - "A circular firing squad: How technologies drag frontend down"
Evgeny Gusev - "A circular firing squad: How technologies drag frontend down"Evgeny Gusev - "A circular firing squad: How technologies drag frontend down"
Evgeny Gusev - "A circular firing squad: How technologies drag frontend down"
 
Vladimir Grinenko - "Dependencies in component web done right"
Vladimir Grinenko - "Dependencies in component web done right"Vladimir Grinenko - "Dependencies in component web done right"
Vladimir Grinenko - "Dependencies in component web done right"
 
Dmitry Bartalevich - "How to train your WebVR"
Dmitry Bartalevich - "How to train your WebVR"Dmitry Bartalevich - "How to train your WebVR"
Dmitry Bartalevich - "How to train your WebVR"
 
Aleksey Bogachuk - "Offline Second"
Aleksey Bogachuk - "Offline Second"Aleksey Bogachuk - "Offline Second"
Aleksey Bogachuk - "Offline Second"
 
James Allardice - "Building a better login with the credential management API"
James Allardice - "Building a better login with the credential management API"James Allardice - "Building a better login with the credential management API"
James Allardice - "Building a better login with the credential management API"
 
Fedor Skuratov "Dark Social: as messengers change the market of social media ...
Fedor Skuratov "Dark Social: as messengers change the market of social media ...Fedor Skuratov "Dark Social: as messengers change the market of social media ...
Fedor Skuratov "Dark Social: as messengers change the market of social media ...
 
Андрей Зайчиков "Архитектура распределенных кластеров NoSQL на AWS"
Андрей Зайчиков "Архитектура распределенных кластеров NoSQL на AWS"Андрей Зайчиков "Архитектура распределенных кластеров NoSQL на AWS"
Андрей Зайчиков "Архитектура распределенных кластеров NoSQL на AWS"
 
Алексей Рагозин "Java и linux борьба за микросекунды"
Алексей Рагозин "Java и linux борьба за микросекунды"Алексей Рагозин "Java и linux борьба за микросекунды"
Алексей Рагозин "Java и linux борьба за микросекунды"
 
Volodymyr Lyubinets "Introduction to big data processing with Apache Spark"
Volodymyr Lyubinets "Introduction to big data processing with Apache Spark"Volodymyr Lyubinets "Introduction to big data processing with Apache Spark"
Volodymyr Lyubinets "Introduction to big data processing with Apache Spark"
 
Наш ответ Uber’у
Наш ответ Uber’уНаш ответ Uber’у
Наш ответ Uber’у
 
Александр Крашенинников "Hadoop High Availability: опыт Badoo"
Александр Крашенинников "Hadoop High Availability: опыт Badoo"Александр Крашенинников "Hadoop High Availability: опыт Badoo"
Александр Крашенинников "Hadoop High Availability: опыт Badoo"
 
Leonid Vasilyev "Building, deploying and running production code at Dropbox"
Leonid Vasilyev  "Building, deploying and running production code at Dropbox"Leonid Vasilyev  "Building, deploying and running production code at Dropbox"
Leonid Vasilyev "Building, deploying and running production code at Dropbox"
 
Анатолий Пласковский "Миллионы карточных платежей за месяц, или как потерять ...
Анатолий Пласковский "Миллионы карточных платежей за месяц, или как потерять ...Анатолий Пласковский "Миллионы карточных платежей за месяц, или как потерять ...
Анатолий Пласковский "Миллионы карточных платежей за месяц, или как потерять ...
 
Mete Atamel "Resilient microservices with kubernetes"
Mete Atamel "Resilient microservices with kubernetes"Mete Atamel "Resilient microservices with kubernetes"
Mete Atamel "Resilient microservices with kubernetes"
 

Recently uploaded

Life upper-Intermediate B2 Workbook for student
Life upper-Intermediate B2 Workbook for studentLife upper-Intermediate B2 Workbook for student
Life upper-Intermediate B2 Workbook for student
NgcHiNguyn25
 
Assessment and Planning in Educational technology.pptx
Assessment and Planning in Educational technology.pptxAssessment and Planning in Educational technology.pptx
Assessment and Planning in Educational technology.pptx
Kavitha Krishnan
 
Natural birth techniques - Mrs.Akanksha Trivedi Rama University
Natural birth techniques - Mrs.Akanksha Trivedi Rama UniversityNatural birth techniques - Mrs.Akanksha Trivedi Rama University
Natural birth techniques - Mrs.Akanksha Trivedi Rama University
Akanksha trivedi rama nursing college kanpur.
 
Main Java[All of the Base Concepts}.docx
Main Java[All of the Base Concepts}.docxMain Java[All of the Base Concepts}.docx
Main Java[All of the Base Concepts}.docx
adhitya5119
 
How to Build a Module in Odoo 17 Using the Scaffold Method
How to Build a Module in Odoo 17 Using the Scaffold MethodHow to Build a Module in Odoo 17 Using the Scaffold Method
How to Build a Module in Odoo 17 Using the Scaffold Method
Celine George
 
South African Journal of Science: Writing with integrity workshop (2024)
South African Journal of Science: Writing with integrity workshop (2024)South African Journal of Science: Writing with integrity workshop (2024)
South African Journal of Science: Writing with integrity workshop (2024)
Academy of Science of South Africa
 
How to Manage Your Lost Opportunities in Odoo 17 CRM
How to Manage Your Lost Opportunities in Odoo 17 CRMHow to Manage Your Lost Opportunities in Odoo 17 CRM
How to Manage Your Lost Opportunities in Odoo 17 CRM
Celine George
 
S1-Introduction-Biopesticides in ICM.pptx
S1-Introduction-Biopesticides in ICM.pptxS1-Introduction-Biopesticides in ICM.pptx
S1-Introduction-Biopesticides in ICM.pptx
tarandeep35
 
Azure Interview Questions and Answers PDF By ScholarHat
Azure Interview Questions and Answers PDF By ScholarHatAzure Interview Questions and Answers PDF By ScholarHat
Azure Interview Questions and Answers PDF By ScholarHat
Scholarhat
 
Lapbook sobre os Regimes Totalitários.pdf
Lapbook sobre os Regimes Totalitários.pdfLapbook sobre os Regimes Totalitários.pdf
Lapbook sobre os Regimes Totalitários.pdf
Jean Carlos Nunes Paixão
 
PCOS corelations and management through Ayurveda.
PCOS corelations and management through Ayurveda.PCOS corelations and management through Ayurveda.
PCOS corelations and management through Ayurveda.
Dr. Shivangi Singh Parihar
 
Digital Artefact 1 - Tiny Home Environmental Design
Digital Artefact 1 - Tiny Home Environmental DesignDigital Artefact 1 - Tiny Home Environmental Design
Digital Artefact 1 - Tiny Home Environmental Design
amberjdewit93
 
Pride Month Slides 2024 David Douglas School District
Pride Month Slides 2024 David Douglas School DistrictPride Month Slides 2024 David Douglas School District
Pride Month Slides 2024 David Douglas School District
David Douglas School District
 
The basics of sentences session 6pptx.pptx
The basics of sentences session 6pptx.pptxThe basics of sentences session 6pptx.pptx
The basics of sentences session 6pptx.pptx
heathfieldcps1
 
ANATOMY AND BIOMECHANICS OF HIP JOINT.pdf
ANATOMY AND BIOMECHANICS OF HIP JOINT.pdfANATOMY AND BIOMECHANICS OF HIP JOINT.pdf
ANATOMY AND BIOMECHANICS OF HIP JOINT.pdf
Priyankaranawat4
 
বাংলাদেশ অর্থনৈতিক সমীক্ষা (Economic Review) ২০২৪ UJS App.pdf
বাংলাদেশ অর্থনৈতিক সমীক্ষা (Economic Review) ২০২৪ UJS App.pdfবাংলাদেশ অর্থনৈতিক সমীক্ষা (Economic Review) ২০২৪ UJS App.pdf
বাংলাদেশ অর্থনৈতিক সমীক্ষা (Economic Review) ২০২৪ UJS App.pdf
eBook.com.bd (প্রয়োজনীয় বাংলা বই)
 
RPMS TEMPLATE FOR SCHOOL YEAR 2023-2024 FOR TEACHER 1 TO TEACHER 3
RPMS TEMPLATE FOR SCHOOL YEAR 2023-2024 FOR TEACHER 1 TO TEACHER 3RPMS TEMPLATE FOR SCHOOL YEAR 2023-2024 FOR TEACHER 1 TO TEACHER 3
RPMS TEMPLATE FOR SCHOOL YEAR 2023-2024 FOR TEACHER 1 TO TEACHER 3
IreneSebastianRueco1
 
Pollock and Snow "DEIA in the Scholarly Landscape, Session One: Setting Expec...
Pollock and Snow "DEIA in the Scholarly Landscape, Session One: Setting Expec...Pollock and Snow "DEIA in the Scholarly Landscape, Session One: Setting Expec...
Pollock and Snow "DEIA in the Scholarly Landscape, Session One: Setting Expec...
National Information Standards Organization (NISO)
 
BÀI TẬP BỔ TRỢ TIẾNG ANH 8 CẢ NĂM - GLOBAL SUCCESS - NĂM HỌC 2023-2024 (CÓ FI...
BÀI TẬP BỔ TRỢ TIẾNG ANH 8 CẢ NĂM - GLOBAL SUCCESS - NĂM HỌC 2023-2024 (CÓ FI...BÀI TẬP BỔ TRỢ TIẾNG ANH 8 CẢ NĂM - GLOBAL SUCCESS - NĂM HỌC 2023-2024 (CÓ FI...
BÀI TẬP BỔ TRỢ TIẾNG ANH 8 CẢ NĂM - GLOBAL SUCCESS - NĂM HỌC 2023-2024 (CÓ FI...
Nguyen Thanh Tu Collection
 
ISO/IEC 27001, ISO/IEC 42001, and GDPR: Best Practices for Implementation and...
ISO/IEC 27001, ISO/IEC 42001, and GDPR: Best Practices for Implementation and...ISO/IEC 27001, ISO/IEC 42001, and GDPR: Best Practices for Implementation and...
ISO/IEC 27001, ISO/IEC 42001, and GDPR: Best Practices for Implementation and...
PECB
 

Recently uploaded (20)

Life upper-Intermediate B2 Workbook for student
Life upper-Intermediate B2 Workbook for studentLife upper-Intermediate B2 Workbook for student
Life upper-Intermediate B2 Workbook for student
 
Assessment and Planning in Educational technology.pptx
Assessment and Planning in Educational technology.pptxAssessment and Planning in Educational technology.pptx
Assessment and Planning in Educational technology.pptx
 
Natural birth techniques - Mrs.Akanksha Trivedi Rama University
Natural birth techniques - Mrs.Akanksha Trivedi Rama UniversityNatural birth techniques - Mrs.Akanksha Trivedi Rama University
Natural birth techniques - Mrs.Akanksha Trivedi Rama University
 
Main Java[All of the Base Concepts}.docx
Main Java[All of the Base Concepts}.docxMain Java[All of the Base Concepts}.docx
Main Java[All of the Base Concepts}.docx
 
How to Build a Module in Odoo 17 Using the Scaffold Method
How to Build a Module in Odoo 17 Using the Scaffold MethodHow to Build a Module in Odoo 17 Using the Scaffold Method
How to Build a Module in Odoo 17 Using the Scaffold Method
 
South African Journal of Science: Writing with integrity workshop (2024)
South African Journal of Science: Writing with integrity workshop (2024)South African Journal of Science: Writing with integrity workshop (2024)
South African Journal of Science: Writing with integrity workshop (2024)
 
How to Manage Your Lost Opportunities in Odoo 17 CRM
How to Manage Your Lost Opportunities in Odoo 17 CRMHow to Manage Your Lost Opportunities in Odoo 17 CRM
How to Manage Your Lost Opportunities in Odoo 17 CRM
 
S1-Introduction-Biopesticides in ICM.pptx
S1-Introduction-Biopesticides in ICM.pptxS1-Introduction-Biopesticides in ICM.pptx
S1-Introduction-Biopesticides in ICM.pptx
 
Azure Interview Questions and Answers PDF By ScholarHat
Azure Interview Questions and Answers PDF By ScholarHatAzure Interview Questions and Answers PDF By ScholarHat
Azure Interview Questions and Answers PDF By ScholarHat
 
Lapbook sobre os Regimes Totalitários.pdf
Lapbook sobre os Regimes Totalitários.pdfLapbook sobre os Regimes Totalitários.pdf
Lapbook sobre os Regimes Totalitários.pdf
 
PCOS corelations and management through Ayurveda.
PCOS corelations and management through Ayurveda.PCOS corelations and management through Ayurveda.
PCOS corelations and management through Ayurveda.
 
Digital Artefact 1 - Tiny Home Environmental Design
Digital Artefact 1 - Tiny Home Environmental DesignDigital Artefact 1 - Tiny Home Environmental Design
Digital Artefact 1 - Tiny Home Environmental Design
 
Pride Month Slides 2024 David Douglas School District
Pride Month Slides 2024 David Douglas School DistrictPride Month Slides 2024 David Douglas School District
Pride Month Slides 2024 David Douglas School District
 
The basics of sentences session 6pptx.pptx
The basics of sentences session 6pptx.pptxThe basics of sentences session 6pptx.pptx
The basics of sentences session 6pptx.pptx
 
ANATOMY AND BIOMECHANICS OF HIP JOINT.pdf
ANATOMY AND BIOMECHANICS OF HIP JOINT.pdfANATOMY AND BIOMECHANICS OF HIP JOINT.pdf
ANATOMY AND BIOMECHANICS OF HIP JOINT.pdf
 
বাংলাদেশ অর্থনৈতিক সমীক্ষা (Economic Review) ২০২৪ UJS App.pdf
বাংলাদেশ অর্থনৈতিক সমীক্ষা (Economic Review) ২০২৪ UJS App.pdfবাংলাদেশ অর্থনৈতিক সমীক্ষা (Economic Review) ২০২৪ UJS App.pdf
বাংলাদেশ অর্থনৈতিক সমীক্ষা (Economic Review) ২০২৪ UJS App.pdf
 
RPMS TEMPLATE FOR SCHOOL YEAR 2023-2024 FOR TEACHER 1 TO TEACHER 3
RPMS TEMPLATE FOR SCHOOL YEAR 2023-2024 FOR TEACHER 1 TO TEACHER 3RPMS TEMPLATE FOR SCHOOL YEAR 2023-2024 FOR TEACHER 1 TO TEACHER 3
RPMS TEMPLATE FOR SCHOOL YEAR 2023-2024 FOR TEACHER 1 TO TEACHER 3
 
Pollock and Snow "DEIA in the Scholarly Landscape, Session One: Setting Expec...
Pollock and Snow "DEIA in the Scholarly Landscape, Session One: Setting Expec...Pollock and Snow "DEIA in the Scholarly Landscape, Session One: Setting Expec...
Pollock and Snow "DEIA in the Scholarly Landscape, Session One: Setting Expec...
 
BÀI TẬP BỔ TRỢ TIẾNG ANH 8 CẢ NĂM - GLOBAL SUCCESS - NĂM HỌC 2023-2024 (CÓ FI...
BÀI TẬP BỔ TRỢ TIẾNG ANH 8 CẢ NĂM - GLOBAL SUCCESS - NĂM HỌC 2023-2024 (CÓ FI...BÀI TẬP BỔ TRỢ TIẾNG ANH 8 CẢ NĂM - GLOBAL SUCCESS - NĂM HỌC 2023-2024 (CÓ FI...
BÀI TẬP BỔ TRỢ TIẾNG ANH 8 CẢ NĂM - GLOBAL SUCCESS - NĂM HỌC 2023-2024 (CÓ FI...
 
ISO/IEC 27001, ISO/IEC 42001, and GDPR: Best Practices for Implementation and...
ISO/IEC 27001, ISO/IEC 42001, and GDPR: Best Practices for Implementation and...ISO/IEC 27001, ISO/IEC 42001, and GDPR: Best Practices for Implementation and...
ISO/IEC 27001, ISO/IEC 42001, and GDPR: Best Practices for Implementation and...
 

Alexey Buzdin "Maslow's Pyramid of Android Testing"

  • 1.
  • 3.
  • 4.
  • 10. Unit Test ๏ Uses simple JUnit ๏ Runs on JVM, not on a device ๏ Lightning fast (5k test in 10 seconds) ๏ Needs Android SDK Stubs
  • 11. static protected void markConflicting(ArrayList<ScheduleItem> items) { for (int i=0; i<items.size(); i++) { ScheduleItem item = items.get(i); // Notice that we only care about sessions when checking conflicts. if (item.type == ScheduleItem.SESSION) for (int j=i+1; j<items.size(); j++) { ScheduleItem other = items.get(j); if (item.type == ScheduleItem.SESSION) { if (intersect(other, item, true)) { other.flags |= ScheduleItem.FLAG_CONFLICTS_WITH_PREVIOUS; item.flags |= ScheduleItem.FLAG_CONFLICTS_WITH_NEXT; } else { // we assume the list is ordered by starttime break; } } } } } https://github.com/google/iosched
  • 12. @Override public void displayData(final SessionFeedbackModel model, final SessionFeedbackQueryEnum query) { switch (query) { case SESSION: mTitle.setText(model.getSessionTitle()); if (!TextUtils.isEmpty(model.getSessionSpeakers())) { mSpeakers.setText(model.getSessionSpeakers()); } else { mSpeakers.setVisibility(View.GONE); } AnalyticsHelper.sendScreenView("Feedback: " + model.getSessionTitle()); break; } } https://github.com/google/iosched
  • 13. java.lang.RuntimeException: Method setText in android.widget.TextView not mocked. See http://g.co/androidstudio/not-mocked for details. at android.widget.TextView.setText(TextView.java) at lv.buzdin.alexey.MainActivityPresenterTest.test(MainActivityPresenterTest.java:39) @Test public void name() throws Exception { TextView textView = new TextView(null); textView.setText("hello"); }
  • 17. Testable architecture ๏ Use MV* Patterns ๏ Dependency Injection is a must ๏ Try to use POJOs where possible ๏ Wrap static Android classes to Services (Log, Toast, etc) ๏ Avoid highly coupling to android classes in * code
  • 18. Model - View - Whatever (Activity/Fragment) ๏ Activity is polluted. (Lifecycle Logic, LayoutInflater, static calls, etc) ๏ We need a POJO
  • 19. @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); BaseApplication.inject(this); setContentView(R.layout.activity_screen); presenter.initPresenter(this); presenter.initNavigationDrawer(); presenter.openScheduleScreen(); if (presenter.firstApplicationStart()) { presenter.openNavigationDrawer(); } }
  • 20. public class MainActivityPresenter { … public void initPresenter(ActionBarActivity activity) { this.activity = activity; ButterKnife.inject(this, activity); } public void initNavigationDrawer() { activity.setSupportActionBar(toolbar); drawerToggle = new ActionBarDrawerToggle(activity, drawerLayout, R.string.app_name, R.string.app_name) { @Override public void onDrawerOpened(View drawerView) { super.onDrawerOpened(drawerView); listView.invalidateViews(); //Refresh counter for bookmarks } }; drawerToggle.setDrawerIndicatorEnabled(true); drawerLayout.setDrawerListener(drawerToggle); activity.getSupportActionBar().setDisplayHomeAsUpEnabled(true); activity.getSupportActionBar().setHomeButtonEnabled(true); listView.setAdapter(navigationAdapter); } }
  • 21. Testable architecture ๏ Use MV* Patterns ๏ Dependency Injection is a must ๏ Try to use POJOs where possible ๏ Wrap static Android classes to Services (Log, Toast, etc) ๏ Avoid highly coupling to android classes in * code
  • 22. Dagger 2 The fastest Java DI Framework! https://google.github.io/dagger/
  • 23. @Singleton public class MainActivityPresenter { @Inject SocialNetworkNavigationService socialsService; @Inject SharedPrefsService preferences; @Inject NavigationAdapter navigationAdapter; … public boolean firstApplicationStart() { boolean subsequentStart = preferences.getBool(PreferencesConstants.SUBSEQUENT_START); if (!subsequentStart) { preferences.setBool(PreferencesConstants.SUBSEQUENT_START, true); return true; } return false; } }
  • 24. Testable architecture ๏ Use MV* Patterns ๏ Dependency Injection is a must ๏ Try to use POJOs where possible ๏ Wrap static Android classes to Services (Log, Toast, etc) ๏ Avoid highly coupling to android classes in * code
  • 25. public class SharedPrefsService { @Inject public Context context; private SharedPreferences getPrefs() { return PreferenceManager.getDefaultSharedPreferences(context); } public boolean getBool(String key) { return getPrefs().getBoolean(key, false); } public void setBool(String key, boolean value) { getPrefs().edit().putBoolean(key, value).commit(); } }
  • 26. Testable architecture ๏ Use MV* Patterns ๏ Dependency Injection is a must ๏ Try to use POJOs where possible ๏ Wrap static Android classes to Services (Log, Toast, etc) ๏ Avoid highly coupling to android classes in * code
  • 27. Removes View dependency for Whatever Button b = (Button)findViewById(R.id.button); b.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { b.setBackgroundColor(Red); } });
  • 28. @InjectView(R.id.button) Button b; @OnClick(R.id.button) public void onClick(View v) { b.setBackgroundColor(Red); } Removes View dependency for Whatever
  • 29. RxBus rxBus = new RxBus(); @InjectView(R.id.button) Button b; Observable<Void> clicks = RxView.clicks(b); public init() { clicks.subscribe(aVoid -> { rxBus.send(new Click()); }); rxBus.toObserverable() .filter(e -> e instanceof Click) .subscribe(e -> { b.setBackgroundColor(Red); }); } https://github.com/JakeWharton/RxBinding Testable architecture with Rx
  • 30. @Test public void test() throws Exception { MyFragment fragment = new MyFragment(); fragment.b = new Button(null) { @Override public void setBackgroundColor(int color) { assertEquals(color, Red); } }; fragment.clicks = Observable.just(null); fragment.init(); }
  • 32. Object o = mock(Object.class); doReturn(true).when(o).equals(any()); Object o = spy(“Hi”); doReturn(true).when(o).equals(any()); o.hashCode() -> is real
  • 33. @RunWith(MockitoJUnitRunner.class) public class MyClassTest { @InjectMocks MyFragment fragment; @Mock Button b; @Test public void test() throws Exception { fragment.clicks = Observable.just(null); fragment.init(); verify(b).setBackgroundColor(Red); } }
  • 36. @RunWith(PowerMockRunner.class) @PrepareForTest( { Toast.class }) public class PowerMockExample { @Test public void testPowerMock() throws Exception { Toast mock = mock(Toast.class); mockStatic(Toast.class); when(Toast.makeText(any(), anyString(), anyInt())).thenReturn(mock); Toast.makeText(null, "1", Toast.LENGTH_SHORT).show(); } }
  • 37. JUnit Extra Features Helpful for Android Developers
  • 38.
  • 39. JUnit Lifecycle public class RunnerTest { @BeforeClass public static void beforeClass() { out.println("Before Class");} @Before public void before() { out.println("Before");} @Test public void test() { out.println("Test"); } @After public void after() { out.println("After"); } @AfterClass public static void afterClass() { out.println("After Class"); } }
  • 40. JUnit Lifecycle public class RunnerTest { @BeforeClass public static void beforeClass() { out.println("Before Class");} @Before public void before() { out.println("Before");} @Test public void test() { out.println("Test"); } @After public void after() { out.println("After"); } @AfterClass public static void afterClass() { out.println("After Class"); } } Before Class Before Test After After Class Process finished with exit code 0
  • 42. public class CustomRunner extends BlockJUnit4ClassRunner{ public static void runnerBefore() { System.out.println("Runner Before");} public static void runnerBeforeClass() { System.out.println("Runner Before Class"); } public static void runnerAfter() { System.out.println("Runner After");} public static void runnerAfterClass() { System.out.println("Runner After Class"); } @Override protected Statement withBefores(FrameworkMethod method, Object t, Statement st) { List<FrameworkMethod> list = getFrameworkMethods("runnerBefore"); return new RunBefores(super.withBefores(method, t, st), list, t); } …. private List<FrameworkMethod> getFrameworkMethods(String methodName) { try { Method runnerBefore = getClass().getDeclaredMethod(methodName); return Collections.singletonList(new FrameworkMethod(runnerBefore)); } catch (Exception e) { throw new RuntimeException(e); } } }
  • 43. @RunWith(CustomRunner.class) public class RunnerTest { …. } Runner Before Class Before Class Runner Before Before Test After Runner After After Class Runner After Class Process finished with exit code 0
  • 44. @RunWith(CustomRunner.class) public class RunnerTest { …. } Runner Before Class Before Class Runner Before Before Test After Runner After After Class Runner After Class Process finished with exit code 0 AndroidJUnitRunner + MockitoJUnitRunner + Parametrized
  • 45.
  • 46. JUnit Rules •Rules allow flexible addition of the behaviour of each test method in a test class •Base Rules Provided in JUnit: Temporary Folder Rule; ExternalResource Rule; ErrorCollector Rule; TestName Rule; Timeout Rule; RuleChain
  • 47. public class CustomRule implements TestRule { private boolean classRule; public CustomRule(boolean classRule) { this.classRule = classRule; } @Override public Statement apply(Statement base, Description description) { return new Statement() { @Override public void evaluate() throws Throwable { System.out.println(classRule ? "Class Rule Before" : "Rule Before"); try { base.evaluate(); } finally { System.out.println(classRule ? "Class Rule After" : "Rule After”); } } }; } }
  • 48. @RunWith(CustomRunner.class) public class RunnerTest { @ClassRule public static CustomRule classRule = new CustomRule(true); @Rule public CustomRule rule = new CustomRule(false); @BeforeClass public static void beforeClass() { out.println("Before Class");} @Before public void before() { out.println("Before");} @Test public void test() { out.println("Test"); } @After public void after() { out.println("After"); } @AfterClass public static void afterClass() { out.println("After Class"); } }
  • 49. Class Rule Before Runner Before Class Before Class Rule Before Runner Before Before Test After Runner After Rule After After Class Runner After Class Class Rule After
  • 50. Class Rule Before Runner Before Class Before Class Rule Before Runner Before Before Test After Runner After Rule After After Class Runner After Class Class Rule After
  • 51. public static class UseRuleChain { @Rule public RuleChain chain= RuleChain .outerRule(new LoggingRule("outer rule") .around(new LoggingRule("middle rule") .around(new LoggingRule("inner rule"); @Test public void example() { assertTrue(true); } } starting outer rule starting middle rule starting inner rule finished inner rule finished middle rule finished outer rule
  • 53. Test Specification 1. Preparation 2. Testable Action 3. Assertion
  • 54. Test Specification 1. Preparation 2. Testable Action 3. Assertion https://github.com/hamcrest/JavaHamcrest assertThat(T object, Matcher<T> matcher)
  • 55. @Test public void testValidIPAddress() throws InvalidIPAddressException { IPAddress addr = new IPAddress("127.0.0.1"); byte[] octets = addr.getOctets(); assertTrue(octets[0] == 127); assertTrue(octets[1] == 0); assertTrue(octets[2] == 0); assertTrue(octets[3] == 1); } Bad Test
  • 56. Examples •assertThat(2, is(2)) •assertThat(“s”, is(nullValue())) •assertThat(“s”, is(new String(“s”))) •assertThat(“s”, equalTo(new String(“s”))) •assertThat(“s”, not(equalTo(“d”))) •assertThat(“s”, instanceOf(String.class)) http://hamcrest.org/JavaHamcrest/javadoc/1.3/
  • 57. List matcher •assertThat(ids, hasItem(10)) •assertThat(ids, contains(5, 8)) •assertThat(ids, containsInAnyOrder(5, 8)) •assertThat(ids, everyItem(greaterThan(3)))
  • 58. AllOf AnyOf assertThat(name, anyOf(startsWith(“A”), endsWith(“B”))) assertThat(ids, allOf( hasSize(5), hasItem(10), everyItem(greaterThan(3)) ))
  • 61. Custom matchers private Matcher<Foo> hasNumber(final int i) { return new TypeSafeMatcher<Foo>() { @Override public void describeTo(final Description description) { description.appendText("getNumber should return ").appendValue(i); } @Override protected void describeMismatchSafely(final Foo item, final Description mismatchDescription) { mismatchDescription.appendText(" was ").appendValue(item.getNumber()); } @Override protected boolean matchesSafely(final Foo item) { return i == item.getNumber(); } }; }
  • 62. hamcrest-rx Matcher<TestSubscriber<T>> hasValues(final Matcher<? super List<T>> eventsMatcher) Matcher<TestSubscriber<T>> hasOnlyValues(final Matcher<? super List<T>> values) Matcher<TestSubscriber<T>> hasOnlyValue(final Matcher<? super T> valueMatcher) Matcher<TestSubscriber<T>> hasNoValues() Matcher<TestSubscriber<T>> hasErrors(final Matcher<? super List<Throwable>> err) Matcher<TestSubscriber<T>> hasNoErrors() Matcher<TestSubscriber<T>> hasOnlyErrors(final Matcher<? super List<Throwable>> err) https://github.com/zalando-incubator/undertaking/blob/master/src/test/java/org/ zalando/undertaking/test/rx/hamcrest/TestSubscriberMatchers.java
  • 63. https://github.com/hertzsprung/hamcrest-json assertThat( "{"age":43, "friend_ids":[16, 52, 23]}", sameJSONAs("{"friend_ids":[52, 23, 16]}") .allowingExtraUnexpectedFields() .allowingAnyArrayOrdering()); hamcrest-json
  • 66. Square Burst https://github.com/square/burst public enum Soda { PEPSI, COKE } public enum Sets { HASH_SET() { @Override public <T> Set<T> create() { return new HashSet<T>(); } }, LINKED_HASH_SET() { … }, TREE_SET() { … } public abstract <T> Set<T> create(); }
  • 67. https://github.com/square/burst @RunWith(BurstJUnit4.class) public class DrinkSodaTest { @Burst Soda soda; @Burst Sets sets; @Test public void drinkFavoriteSodas(Soda soda) { // TODO Test drink method with 'soda'... } } Square Burst
  • 68. https://github.com/square/burst @RunWith(BurstJUnit4.class) public class DrinkSodaTest { private final Set<Soda> favorites; public DrinkSodaTest(Sets sets) { favorites = sets.create(); } @Test public void trackFavorites() { // TODO … } @Test public void drinkFavoriteSodas(Soda soda) { //TODO … } } Square Burst
  • 69. JUnitParams https://github.com/Pragmatists/JUnitParams @RunWith(JUnitParamsRunner.class) public class PersonTest { @Test @Parameters({"17, false”, "22, true" }) public void personIsAdult(int age, boolean valid) throws Exception { assertThat(new Person(age).isAdult(), is(valid)); } }
  • 70. Enclosed Provides a way to use multiple JUnit Runners in a test class
  • 71.
  • 73. http://junit.org/junit5/ JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; class FirstJUnit5Tests { @Test void myFirstTest() { assertEquals(2, 1 + 1); } }
  • 75. Grouped Assertions @Test void groupedAssertions() { // In a grouped assertion all assertions are executed, and any // failures will be reported together. assertAll("address", () -> assertEquals("John", address.getFirstName()), () -> assertEquals("User", address.getLastName()) ); }
  • 76. Throwable Assertions @Test void exceptionTesting() { Throwable exception = assertThrows(IllegalArgumentException.class, () -> { throw new IllegalArgumentException("a message"); }); assertEquals("a message", exception.getMessage()); }
  • 77. No assertThat() import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import org.junit.jupiter.api.Test; class HamcrestAssertionDemo { @Test void assertWithHamcrestMatcher() { assertThat(2 + 1, is(equalTo(3))); } }
  • 78. No Runners or Rules > Extensions @ExtendWith(MockitoExtension.class) class MyMockitoTest { @BeforeEach void init(@Mock Person person) { when(person.getName()).thenReturn("Dilbert"); } @Test void simpleTestWithInjectedMock(@Mock Person person) { assertEquals("Dilbert", person.getName()); } }
  • 79. Dynamic Tests class DynamicTestsDemo { @TestFactory Collection<DynamicTest> dynamicTestsFromCollection() { return Arrays.asList( dynamicTest("1st dynamic test", () -> assertTrue(true)), dynamicTest("2nd dynamic test", () -> assertEquals(4, 2 * 2)) ); } } Collection, Iterable, Iterator, Stream
  • 80. in Android • Not coming soon • Would require a rewrite for all testing libraries • Would require Android Studio support • Would simplify the Extension model https://github.com/junit-team/junit5/issues/204
  • 81. Integration Tests ๏ Uses Robolectric framework ๏ Runs on JVM with Shadow Android SDK ๏ Has access to Context and all Android peripheral
  • 82. Robolectric @RunWith(RobolectricTestRunner.class) public class MyActivityTest { @Test public void clickingButton_shouldChangeResultsViewText() throws Exception { MyActivity activity = Robolectric.setupActivity(MyActivity.class); Button button = (Button) activity.findViewById(R.id.button); TextView results = (TextView) activity.findViewById(R.id.results); button.performClick(); assertThat(results.getText().toString()).isEqualTo("Robolectric Rocks!"); } }
  • 83. ActivityController controller = Robolectric.buildActivity(MyAwesomeActivity.class).create().start(); Activity activity = controller.get(); // assert that something hasn't happened activityController.resume(); // assert it happened! Activity activity = Robolectric.buildActivity(MyAwesomeActivity.class) .create().start().resume().visible().get(); Activity Lifecycle
  • 84. public class SharedPrefsService { @Inject public Context context; private SharedPreferences getPrefs() { return PreferenceManager.getDefaultSharedPreferences(context); } public boolean getBool(String key) { return getPrefs().getBoolean(key, false); } public void setBool(String key, boolean value) { getPrefs().edit().putBoolean(key, value).commit(); } }
  • 85. Robolectric ๏ Life saver when complex Android SDK calls should be tested ๏ Slow compared to Unit Tests ๏ Not up to date to the latest SDKs (API 24 not supported yet)
  • 86. UI Tests ๏ Runs on actual Android Device ๏ Slower the Unit tests ๏ Brittle and dependant on device health
  • 87. public void testRecorded() throws Exception { if (solo.waitForText("Hello!")) { solo.clickOnView(solo.findViewById("R.id.sign_in")); solo.enterText((EditText) solo.findViewById("R.id.login_username"),"username"); solo.enterText((EditText) solo.findViewById("R.id.login_password"),"password"); solo.clickOnView(solo.findViewById("R.id.login_login")); solo.waitForActivity("HomeTabActivity"); } solo.clickOnView(solo.findViewById("R.id.menu_compose_tweet") ); solo.enterText((EditText) solo.findViewById(“R.id.edit"), "Testdroid"); solo.clickOnView(solo.findViewById("R.id.composer_post")); } Robotium
  • 88. Android Espresso @Test
 public void multiActivityTest() {
 onView(withId(R.id.date))
 .perform(click());
 // Loads another activity riiiight here
 onView(allOf(withId(R.id.date_expanded), withText("SomeRandomDate")))
 .check(matches(isDisplayed()))
 .perform(click());
 // Yay! No waiting!
 }
  • 89. Espresso comes with Hamcrest integration @Test
 public void dateTest() {
 onView(withId(R.id.date))
 .check(matches(withText("2014-10-15")));
 }
  • 90. Robotium vs Espresso • Espresso faster • Robotium has bigger SDK coverage • Espresso has built in wait mechanism that is optimised for android lifecycle http://www.stevenmarkford.com/android-espresso-vs-robotium- benchmarks/
  • 91. Looking into Cross-platform UI Test Automation?
  • 92.
  • 94.
  • 95. Cross platform tests If you have dedicated QA team and product on multiple platforms - go Calabash or Appium • More flacky tests • Less performant speed • Some test reuse • Easier for QA
  • 97. How to run UI test • Don’t initialize run-time dependencies (event tracking, analytics, long-init things like payment solutions) • Don’t hit up real backend, mock out responses • Insert appropriate test data before test starts running
  • 98. How to mock a Server - Mock Server through DI - Mock HTTP Server instance on Device - Dev instance of Server
  • 99. DI: Create a custom Test Runner public class MockTestRunner extends AndroidJUnitRunner {
 @Override
 public Application newApplication(ClassLoader cl, String className, Context ctx)
 throws InstantiationException, IllegalAccessException, ClassNotFoundException {
 return super.newApplication(cl, MockDemoApplication.class.getName(), ctx);
 }
 }
  • 100. DI: Create a custom Test Application public class MockDemoApplication extends DemoApplication {
 @Override
 protected DemoComponent createComponent() {
 return DaggerMainActivityTest_TestComponent.builder().build();
 }
 }
  • 101. MockServer on Device: AndroidAsync https://github.com/koush/AndroidAsync AsyncHttpServer server = new AsyncHttpServer(); server.get("/", new HttpServerRequestCallback() { @Override public void onRequest(AsyncHttpServerRequest request, AsyncHttpServerResponse response) { response.send("Hello!!!"); } }); server.listen(5000);
  • 102. How to run UI tests on CI?
  • 105. https://github.com/Genymobile/genymotion-gradle-plugin 1. genymotion { 2. devices { 3. nexus5 { 4. template "Google Nexus 5 - 4.4.4 - API 19 - 1080x1920" 5. } 6. } 7. }
  • 109. Conclusion ๏ Unit tests are cheap, make them your first frontier ๏ Adapt code to make it more testable ๏ Structure tests with @Rules and Hamcrest Matchers ๏ Mockito + Powermock will help to mock Android else Robolectric will
  • 110. Conclusion ๏ UI tests are harder to write and maintain ๏ If you have a dedicated mobile QA team think of cross-platform tests ๏ For UI tests have a config for Mocked server and other integration points ๏ Configure either emulator startup or device farm on your CI
  • 111. TESTS ARE MADE TO MAKEYOU FEEL SECURE!
  • 112. LIKE A LOVELY HUG ♥