dat testing - an introduction to java and android testing
Post on 20-Aug-2015
493 Views
Preview:
TRANSCRIPT
public class SaiyanSagaTest { public static final int GOKU_POWER_LEVEL = 10000; public static final String EXPECTED_GOKU_OUTCOME ="It's over nine thousaaaaaaaaand!"; // public Saiyan(KiiSensingInterface sensingMethod) Saiyan goku, vegeta, nappa;
@Before public void setUp() { // KiSense and Scouter classes implement KiSensingInterface goku = new Saiyan(new KiSense()); nappa = new Saiyan(null); vegeta = new Saiyan(new Scouter()); }
@Test public void testVegetaReadsGokusPowerLevel() throws Exception { goku.setPowerLevel(GOKU_POWER_LEVEL); assertThat(EXPECTED_GOKU_OUTCOME, vegeta.scanPowerLevel(goku)); }
@After public void tearDown() { nappa.finish(); }}
public class Tard { // Initialize rest of Tard, it was awful public String getResponse() { return “nope”; }}
public class TardTest { Tard tard = new Tard(); // Look ma’, I’m testing stuff @Test public void testGetTardResponse() throws Exception { assertEquals(EXPECTED_NOPE, tard.getResponse()); }}
public class Fry{ public void shutUpAndTakeMy(Money money) { if (money != null) shutUpAndTakeIt(money); }}
public class FuturamaTest { @Mock Account fryAccount; @Mock BankFactory bank; @Spy Fry fry; // I don’t want to live with this testing anymore @Test public void testIDontHaveAnyMoneyToTake() throws Exception { when(fryAccount.getMoney()).thenReturn(null); verify(fry, never()).shutUpAndTakeIt(fryAccount.getMoney()); }}
public class Snape {
public int pointsToGryffindor(Student student) { if (Student.DANIEL_RADCLIFFE.equalsTo(student)) return -10; else if (Student.EMMA_WATSON.equalsTo(student)) return Integer.MAX_INT;
return 10; }}
public class HogwartsTest { public static int MAX_POINTS = Integer.MAX_INT; @Spy Snape snape; // Bullshit! 2,147,483,647 points to Gryffindor! @Test public void testSnapeGivingPointsToHermione() throws Exception { when(snape.pointsToGryffindor(((Student) any()))).thenReturn(MAX_POINTS); assertEquals(MAX_POINTS, snape.pointsToGryffindor(Student.EMMA_WATSON)); }}
MOCKING & STUBBING
UNIT & INTEGRATION ACCEPTANCE
Mockito JUnit Espresso
JMock Robolectric Robotium
PowerMock CalabashAdditionally JaCoCo can help you on keeping an eye on code coverage.
UNIT F***S EVERYTHING
ELSE*
*Except singletons, UI & race conditions. Those f***ers cannot be tested.
public class MarceusWallace { public void initialization(){ // Lots of stuff concerning intialization this.looksLikeABitch = !(Locale.WHAT.equalTo(this.brett.getLocale()) && Locale.ENGLISH.getDisplayLanguage().equalTo( this.brett.getLocale().getDisplayLanguage()) && this.jules.describeMarceusWallace(this.brett) && this.brett.getWhatCounter() < 7); }}
public class MarceusWallaceTest { @Test public void testMrWallaceDoesNotLookLikeABitch() throws Exception { // Testing all cases would lead to 24 cases plus every branch of the method when(brett.getLocale()).thenReturn(whatLocale); when(brett.getWhatCounter).thenReturn(5); when(whatLocale.getDisplayLanguage()) .thenReturn(Locale.ENGLISH.getDisplayLanguage()); when(jules.describeMarceusWallace(brett)).thenReturn(Boolean.TRUE);
controller.initialize(); assertFalse(controller.doesLookLikeABitch()); }}
public class MarceusWallace {
public void initialization(){ // Nice refactor! this.looksLikeABitch = calculateIsLookingLikeABitch(); }}
public class MarceusWallaceControllerTest { @Test public void testMrWallaceDoesNotLookLikeABitch() throws Exception { // Much better! But what if Jules and Brett are final or cannot be mocked // that would be still a lot of boilerplate! when(controller.calculateIsLookingLikeABitch() .thenReturn(Boolean.FALSE);
controller.initialize(); assertFalse(controller.doesLookLikeABitch()); }}
public class MarceusWallace {
public void initialization(){ // Now I can test calculateIsLooking injecting its dependencies! this.looksLikeABitch = calculateIsLookingLikeABitch(this.brett, this.jules); }}
public class MarceusWallaceControllerTest { @Test public void testMrWallaceDoesNotLookLikeABitch() throws Exception { // Using a spy and injection I can narrow the SUT to the initialization // method. We still have to do 24 cases for testCalculateIsLooking... when(controller.calculateIsLookingLikeABitch(brett, jules)) .thenReturn(Boolean.FALSE); controller.initialize(); assertFalse(controller.doesLookLikeABitch()); }}
public class GruePresenter {
public GruePresenter(Context context){ Crashlytics.start(context); Log.d("GruePresenter", "Crashlytics Initialized"); // Even if you injected this. It would still be wrong mixpanelAPI = MixpanelAPI.getInstance(context, MIXPANEL_TOKEN); new YourFavoriteAsyncTask().execute(new DoSomethingNetworky()); throws new FacepalmException("You got eaten by a Grue!"); }}
public class GruePresenterTest {
@Test(expects = FacepalmException.class) public void testInitialization() throws Exception { GruePresenter presenter = new GruePresenter(Robolectric.application); // Your code is baaaaaaad and you should feel baaaaaaaad }}
public class GruePresenter { // Remember, AsyncTask.execute is final! public void doSomethingAsyncish(){ new YourFavoriteAsyncTask() .execute(new DoSomethingNetworky()); }}
public class CrashlyticsAdapter { public void start(Context context) { Crashlytics.start(context); }}
public class Logger { public void debug(String tag, String msg){ Log.d(tag, msg); }}
public class MixpanelAdapter { // You can inject an instance of Mixpanel public MixpanelWrapper(MixpanelAPI api) { this.api = api; }}
public class GruePresenter {
public GruePresenter(CraslyticsWrapper crashlytics, Logger logger, MixpanelWrapper mixpanelWapper){ crashlytics.start(context); logger.debug("GruePresenter", "Crashlytics Initialized"); this.mixpanelWrapper = mixpanelWrapper; // We had to move the doSomethingAsyncish out of here }}
public class GruePresenterTest {
@Test public void testInitialization() throws Exception { GruePresenter presenter = new GruePresenter(mockCrash, mockLogger, mockMixpanel); doNothing().when(presenter).doSomethingAsyncIsh() // Alright, let’s dance! }}
2.397 Tests● 2.364 units● 33 integration● 1.942 Android -
coupled
~2:30m full test suite
~70% Coverage
Maven 3.2.3● JUnit● Mockito● Robolectric
59 users, 7 crashes
~35K lines of code
1. We are paid to solve problems. Be efficient.
2. Tests test what your code does, not what it should do.
3. If it is not your code, there is no need to test it.
● xUnit Test Patterns: Refactoring Test Code, Gerard Meszaros
o http://xunitpatterns.com/
● 467 tests, 0 failures, 0 confidence, Katrina Owen● Mocks aren’t stubs, Martin Fowler● Eveyrthing you wanted to know about testing, but were afraid to ask, Jorge
Barroso● Exploding Software-Engineering Myths, Janie Chang
Bibliography
top related