@Test public void pickFruits() { final FruitTree mangoTree = context.mock(FruitTree.class); final Mango mango1 = new Mango(); final Mango mango2 = new Mango(); context.checking( new Expectations() { { oneOf(mangoTree).pickFruit(with(any(Collection.class))); will( new VoidAction() { public Object invoke(Invocation invocation) { @SuppressWarnings({"unchecked"}) Collection<Fruit> fruits = (Collection<Fruit>) invocation.getParameter(0); fruits.add(mango1); fruits.add(mango2); return null; } }); } }); Collection<Fruit> fruits = new FruitPicker().pickFruits(asList(mangoTree)); assertEquals(asList(mango1, mango2), fruits); }
@Test public void modelBlowsUpInAnUnavoidableWay() throws Exception { mockery.checking( new Expectations() { { allowing(browseTransactionsModel).findAllTransactions(); will(throwException(new InternalStorageException())); } }); pressExportAllTransactionsButton(browseTransactionsActivity); assertLastToastMatchesRegex( "Something strange just happened. Try again. You might need to reinstall the " + "application. I feel embarrassed and ashamed."); }
@Test public void exportWhateverTheModelProvides() throws Exception { final List<Transaction> anyNonEmptyListOfTransactions = ObjectMother.anyNonEmptyListOfTransactions(); mockery.checking( new Expectations() { { allowing(browseTransactionsModel).findAllTransactions(); will(returnValue(anyNonEmptyListOfTransactions)); ignoring(androidDevicePublicStorageGateway); oneOf(exportAllTransactionsAction).execute(with(anyNonEmptyListOfTransactions)); } }); pressExportAllTransactionsButton(browseTransactionsActivity); }
@Test public void mediaNotAvailable() throws Exception { mockery.checking( new Expectations() { { allowing(browseTransactionsModel).findAllTransactions(); allowing(androidDevicePublicStorageGateway).findPublicExternalStorageDirectory(); will(throwException(new PublicStorageMediaNotAvailableException())); never(exportAllTransactionsAction); } }); pressExportAllTransactionsButton(browseTransactionsActivity); assertLastToastMatchesRegex( "No place to which to export the transactions. Insert an SD card or connect an " + "external storage device and try again."); }
@Test public void exportActionBlowsUpInAnUnavoidableWay() throws Exception { mockery.checking( new Expectations() { { // SMELL How can I ignore these irrelevant details? ignoring(browseTransactionsModel); ignoring(androidDevicePublicStorageGateway); allowing(exportAllTransactionsAction).execute(with(any(List.class))); will(throwException(new InternalStorageException())); } }); pressExportAllTransactionsButton(browseTransactionsActivity); assertLastToastMatchesRegex( "Something strange just happened. Try again. You might need to reinstall the " + "application. I feel embarrassed and ashamed."); }
@Test public void mediaNotWritable() throws Exception { mockery.checking( new Expectations() { { allowing(browseTransactionsModel).findAllTransactions(); allowing(androidDevicePublicStorageGateway).findPublicExternalStorageDirectory(); will( throwException( new PublicStorageMediaNotWritableException( new File("/mnt/sdcard/TrackEveryPenny.csv")))); never(exportAllTransactionsAction); } }); pressExportAllTransactionsButton(browseTransactionsActivity); assertLastToastMatchesRegex( "Permission denied trying to export the transactions to file " + "/mnt/sdcard/TrackEveryPenny.csv"); }
@Test public void happyPath() throws Exception { final Collection<Object> anyValidNonTrivialCollectionOfTransactions = Lists.newArrayList(new Object(), new Object(), new Object()); mockery.checking( new Expectations() { { allowing(browseTransactionsModel).findAllTransactions(); will(returnValue(anyValidNonTrivialCollectionOfTransactions)); // SMELL Irrelevant detail ignoring(androidDevicePublicStorageGateway).findPublicExternalStorageDirectory(); allowing(exportAllTransactionsAction).execute(with(any(List.class))); // succeeds by not throwing an exception } }); pressExportAllTransactionsButton(browseTransactionsActivity); assertLastToastMatchesRegex("Exported all transactions to (.+)\\.csv"); }
@RunWith(RobolectricTestRunner.class) public class HandleExportAllTransactionsTest { private Mockery mockery = new Mockery(); private final BrowseTransactionsModel browseTransactionsModel = mockery.mock(BrowseTransactionsModel.class); private final ExportAllTransactionsAction exportAllTransactionsAction = mockery.mock(ExportAllTransactionsAction.class); private final AndroidDevicePublicStorageGateway androidDevicePublicStorageGateway = mockery.mock(AndroidDevicePublicStorageGateway.class); private final BrowseTransactionsActivity browseTransactionsActivity = new BrowseTransactionsActivity( null, exportAllTransactionsAction, androidDevicePublicStorageGateway, browseTransactionsModel); @Before public void initializeActivity() { browseTransactionsActivity.onCreate(null); browseTransactionsActivity.setCollaborators( exportAllTransactionsAction, androidDevicePublicStorageGateway, browseTransactionsModel); } @Test public void happyPath() throws Exception { final Collection<Object> anyValidNonTrivialCollectionOfTransactions = Lists.newArrayList(new Object(), new Object(), new Object()); mockery.checking( new Expectations() { { allowing(browseTransactionsModel).findAllTransactions(); will(returnValue(anyValidNonTrivialCollectionOfTransactions)); // SMELL Irrelevant detail ignoring(androidDevicePublicStorageGateway).findPublicExternalStorageDirectory(); allowing(exportAllTransactionsAction).execute(with(any(List.class))); // succeeds by not throwing an exception } }); pressExportAllTransactionsButton(browseTransactionsActivity); assertLastToastMatchesRegex("Exported all transactions to (.+)\\.csv"); } @Test public void mediaNotAvailable() throws Exception { mockery.checking( new Expectations() { { allowing(browseTransactionsModel).findAllTransactions(); allowing(androidDevicePublicStorageGateway).findPublicExternalStorageDirectory(); will(throwException(new PublicStorageMediaNotAvailableException())); never(exportAllTransactionsAction); } }); pressExportAllTransactionsButton(browseTransactionsActivity); assertLastToastMatchesRegex( "No place to which to export the transactions. Insert an SD card or connect an " + "external storage device and try again."); } @Test public void mediaNotWritable() throws Exception { mockery.checking( new Expectations() { { allowing(browseTransactionsModel).findAllTransactions(); allowing(androidDevicePublicStorageGateway).findPublicExternalStorageDirectory(); will( throwException( new PublicStorageMediaNotWritableException( new File("/mnt/sdcard/TrackEveryPenny.csv")))); never(exportAllTransactionsAction); } }); pressExportAllTransactionsButton(browseTransactionsActivity); assertLastToastMatchesRegex( "Permission denied trying to export the transactions to file " + "/mnt/sdcard/TrackEveryPenny.csv"); } @Test public void modelBlowsUpInAnUnavoidableWay() throws Exception { mockery.checking( new Expectations() { { allowing(browseTransactionsModel).findAllTransactions(); will(throwException(new InternalStorageException())); } }); pressExportAllTransactionsButton(browseTransactionsActivity); assertLastToastMatchesRegex( "Something strange just happened. Try again. You might need to reinstall the " + "application. I feel embarrassed and ashamed."); } @Test public void exportActionBlowsUpInAnUnavoidableWay() throws Exception { mockery.checking( new Expectations() { { // SMELL How can I ignore these irrelevant details? ignoring(browseTransactionsModel); ignoring(androidDevicePublicStorageGateway); allowing(exportAllTransactionsAction).execute(with(any(List.class))); will(throwException(new InternalStorageException())); } }); pressExportAllTransactionsButton(browseTransactionsActivity); assertLastToastMatchesRegex( "Something strange just happened. Try again. You might need to reinstall the " + "application. I feel embarrassed and ashamed."); } @Test public void exportWhateverTheModelProvides() throws Exception { final List<Transaction> anyNonEmptyListOfTransactions = ObjectMother.anyNonEmptyListOfTransactions(); mockery.checking( new Expectations() { { allowing(browseTransactionsModel).findAllTransactions(); will(returnValue(anyNonEmptyListOfTransactions)); ignoring(androidDevicePublicStorageGateway); oneOf(exportAllTransactionsAction).execute(with(anyNonEmptyListOfTransactions)); } }); pressExportAllTransactionsButton(browseTransactionsActivity); } private void pressExportAllTransactionsButton( BrowseTransactionsActivity browseTransactionsActivity) { browseTransactionsActivity.exportAllTransactions( browseTransactionsActivity.findViewById(R.id.exportAllTransactionsButton)); } public static void assertLastToastMatchesRegex(String patternText) { ShadowHandler.idleMainLooper(); assertThat(ShadowToast.getTextOfLatestToast(), matches(Pattern.compile(patternText))); } }