├── app ├── .gitignore ├── src │ ├── main │ │ ├── res │ │ │ ├── values │ │ │ │ ├── strings.xml │ │ │ │ ├── colors.xml │ │ │ │ └── styles.xml │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ ├── layout │ │ │ │ └── activity_main.xml │ │ │ ├── drawable-v24 │ │ │ │ └── ic_launcher_foreground.xml │ │ │ └── drawable │ │ │ │ └── ic_launcher_background.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── anjan │ │ │ │ └── mockitounittesttutorial │ │ │ │ ├── MessagingService.java │ │ │ │ ├── exercise │ │ │ │ ├── networking │ │ │ │ │ ├── NetworkErrorException.java │ │ │ │ │ └── UpdateUsernameHttpEndpointSync.java │ │ │ │ ├── eventbus │ │ │ │ │ ├── EventBusPoster.java │ │ │ │ │ └── UserDetailsChangedEvent.java │ │ │ │ ├── users │ │ │ │ │ ├── UsersCache.java │ │ │ │ │ └── User.java │ │ │ │ ├── description.txt │ │ │ │ └── UpdateUsernameUseCaseSync.java │ │ │ │ ├── sync │ │ │ │ ├── eventbus │ │ │ │ │ ├── LoggedInEvent.java │ │ │ │ │ └── EventBusPoster.java │ │ │ │ ├── networking │ │ │ │ │ ├── NetworkErrorException.java │ │ │ │ │ └── LoginHttpEndpointSync.java │ │ │ │ ├── authtoken │ │ │ │ │ └── AuthTokenCache.java │ │ │ │ └── LoginUseCaseSync.java │ │ │ │ ├── SMSService.java │ │ │ │ ├── mock │ │ │ │ ├── EmailSender.java │ │ │ │ ├── InvoiceStorage.java │ │ │ │ ├── EventRecorder.java │ │ │ │ ├── Customer.java │ │ │ │ ├── LateInvoiceNotifier.java │ │ │ │ └── Event.java │ │ │ │ ├── EmailService.java │ │ │ │ ├── async │ │ │ │ ├── DummyCallback.java │ │ │ │ ├── db │ │ │ │ │ ├── Logger.java │ │ │ │ │ ├── EntityManager.java │ │ │ │ │ └── CustomerDao.java │ │ │ │ ├── DummyCollaborator.java │ │ │ │ └── DummyCaller.java │ │ │ │ ├── InitialContext.java │ │ │ │ ├── Cache.java │ │ │ │ ├── Point.java │ │ │ │ ├── Utils.java │ │ │ │ ├── LocatorService.java │ │ │ │ ├── stub │ │ │ │ ├── CustomerReader.java │ │ │ │ ├── Customer.java │ │ │ │ └── DbManager.java │ │ │ │ ├── ServiceLocator.java │ │ │ │ ├── MainActivity.java │ │ │ │ ├── contributor │ │ │ │ └── ContributorActivity.java │ │ │ │ └── Locator.java │ │ └── AndroidManifest.xml │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── anjan │ │ │ └── mockitounittesttutorial │ │ │ └── ExampleInstrumentedTest.java │ └── test │ │ └── java │ │ └── com │ │ └── anjan │ │ └── mockitounittesttutorial │ │ ├── stub │ │ └── CustomerReaderTest.java │ │ ├── async │ │ ├── db │ │ │ └── CustomerDaoTest.java │ │ └── DummyCallerTest.java │ │ ├── LocatorTest.java │ │ ├── mock │ │ └── LateInvoiceNotifierTest.java │ │ └── sync │ │ └── LoginUseCaseSyncTest.java ├── proguard-rules.pro └── build.gradle ├── settings.gradle ├── AS.PNG ├── slides ├── Unit test-1.pptx ├── Unit test-2.pptx └── Unit test-3.pptx ├── doc ├── FOSS MileStone 2.pptx ├── FOSS Milestone 1.pptx └── Pull request and merge conflict with rebase.pdf ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── assets └── Unit test Documentation.pdf ├── .idea ├── encodings.xml ├── vcs.xml ├── runConfigurations.xml ├── gradle.xml ├── misc.xml └── codeStyles │ └── Project.xml ├── gradle.properties ├── .github └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── gradlew.bat ├── readme.md ├── CODE-OF-CONDUCT.md ├── gradlew └── CONTRIBUTING.md /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /AS.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anjandebnath/MockitoUnitTestTutorial/HEAD/AS.PNG -------------------------------------------------------------------------------- /slides/Unit test-1.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anjandebnath/MockitoUnitTestTutorial/HEAD/slides/Unit test-1.pptx -------------------------------------------------------------------------------- /slides/Unit test-2.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anjandebnath/MockitoUnitTestTutorial/HEAD/slides/Unit test-2.pptx -------------------------------------------------------------------------------- /slides/Unit test-3.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anjandebnath/MockitoUnitTestTutorial/HEAD/slides/Unit test-3.pptx -------------------------------------------------------------------------------- /doc/FOSS MileStone 2.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anjandebnath/MockitoUnitTestTutorial/HEAD/doc/FOSS MileStone 2.pptx -------------------------------------------------------------------------------- /doc/FOSS Milestone 1.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anjandebnath/MockitoUnitTestTutorial/HEAD/doc/FOSS Milestone 1.pptx -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | MockitoUnitTestTutorial 3 | 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anjandebnath/MockitoUnitTestTutorial/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /assets/Unit test Documentation.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anjandebnath/MockitoUnitTestTutorial/HEAD/assets/Unit test Documentation.pdf -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anjandebnath/MockitoUnitTestTutorial/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anjandebnath/MockitoUnitTestTutorial/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anjandebnath/MockitoUnitTestTutorial/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anjandebnath/MockitoUnitTestTutorial/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anjandebnath/MockitoUnitTestTutorial/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anjandebnath/MockitoUnitTestTutorial/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anjandebnath/MockitoUnitTestTutorial/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anjandebnath/MockitoUnitTestTutorial/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anjandebnath/MockitoUnitTestTutorial/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anjandebnath/MockitoUnitTestTutorial/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /doc/Pull request and merge conflict with rebase.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anjandebnath/MockitoUnitTestTutorial/HEAD/doc/Pull request and merge conflict with rebase.pdf -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/MessagingService.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial; 2 | 3 | public interface MessagingService { 4 | String getMessageBody(); 5 | String getServiceName(); 6 | } 7 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/exercise/networking/NetworkErrorException.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial.exercise.networking; 2 | 3 | public class NetworkErrorException extends Exception { 4 | } 5 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/exercise/eventbus/EventBusPoster.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial.exercise.eventbus; 2 | 3 | public interface EventBusPoster { 4 | 5 | void postEvent(Object event); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/exercise/users/UsersCache.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial.exercise.users; 2 | 3 | public interface UsersCache { 4 | 5 | void cacheUser(User user); 6 | 7 | User getUser(String userId); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/sync/eventbus/LoggedInEvent.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial.sync.eventbus; 2 | 3 | /** 4 | * Created by Anjan Debnath on 7/23/2018. 5 | * Copyright (c) 2018, W3 Engineers Ltd. All rights reserved. 6 | */ 7 | public class LoggedInEvent {} 8 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/sync/networking/NetworkErrorException.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial.sync.networking; 2 | 3 | 4 | /** 5 | * Created by Anjan Debnath on 7/23/2018. 6 | * Copyright (c) 2018, W3 Engineers Ltd. All rights reserved. 7 | */ 8 | public class NetworkErrorException extends Exception { 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/SMSService.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial; 2 | 3 | public class SMSService implements MessagingService { 4 | 5 | public String getMessageBody() { 6 | return "sms message"; 7 | } 8 | 9 | public String getServiceName() { 10 | return "SMSService"; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/mock/EmailSender.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial.mock; 2 | 3 | /** 4 | * Created by Anjan Debnath on 7/25/2018. 5 | * Copyright (c) 2018, W3 Engineers Ltd. All rights reserved. 6 | */ 7 | public class EmailSender { 8 | 9 | public void sendEmail(Customer customer){ 10 | 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/EmailService.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial; 2 | 3 | public class EmailService implements MessagingService { 4 | 5 | public String getMessageBody() { 6 | return "email message"; 7 | } 8 | 9 | public String getServiceName() { 10 | return "EmailService"; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/sync/eventbus/EventBusPoster.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial.sync.eventbus; 2 | 3 | /** 4 | * Created by Anjan Debnath on 7/23/2018. 5 | * Copyright (c) 2018, W3 Engineers Ltd. All rights reserved. 6 | */ 7 | public interface EventBusPoster { 8 | 9 | void postEvent(Object event); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | <<<<<<< HEAD 2 | #Tue Aug 27 13:35:10 BDT 2019 3 | ======= 4 | #Mon Aug 26 16:38:53 BDT 2019 5 | >>>>>>> loical changes 6 | distributionBase=GRADLE_USER_HOME 7 | distributionPath=wrapper/dists 8 | zipStoreBase=GRADLE_USER_HOME 9 | zipStorePath=wrapper/dists 10 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip 11 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/mock/InvoiceStorage.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial.mock; 2 | 3 | /** 4 | * Created by Anjan Debnath on 7/25/2018. 5 | * Copyright (c) 2018, W3 Engineers Ltd. All rights reserved. 6 | */ 7 | public class InvoiceStorage { 8 | 9 | public boolean hasOutstandingInvoice(Customer customer){ 10 | return true; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/sync/authtoken/AuthTokenCache.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial.sync.authtoken; 2 | 3 | /** 4 | * Created by Anjan Debnath on 7/23/2018. 5 | * Copyright (c) 2018, W3 Engineers Ltd. All rights reserved. 6 | */ 7 | public interface AuthTokenCache { 8 | 9 | void cacheAuthToken(String authToken); 10 | 11 | String getAuthToken(); 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/async/DummyCallback.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial.async; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Created by Anjan Debnath on 7/23/2018. 7 | * Copyright (c) 2018, W3 Engineers Ltd. All rights reserved. 8 | */ 9 | public interface DummyCallback { 10 | public void onSuccess(List result); 11 | public void onFail(int code); 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/mock/EventRecorder.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial.mock; 2 | 3 | /** 4 | * Created by Anjan Debnath on 7/25/2018. 5 | * Copyright (c) 2018, W3 Engineers Ltd. All rights reserved. 6 | */ 7 | public class EventRecorder { 8 | 9 | 10 | public void recordEvent(Event event){ 11 | /** 12 | * record event 13 | */ 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/async/db/Logger.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial.async.db; 2 | 3 | /** 4 | * Created by Anjan Debnath on 8/6/2018. 5 | * Copyright (c) 2018, W3 Engineers Ltd. All rights reserved. 6 | */ 7 | public class Logger { 8 | 9 | 10 | public void info(String s, long id) { 11 | 12 | } 13 | 14 | public void error(String missing_customer_information) { 15 | 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/async/db/EntityManager.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial.async.db; 2 | 3 | import com.anjan.mockitounittesttutorial.mock.Customer; /** 4 | * Created by Anjan Debnath on 8/6/2018. 5 | * Copyright (c) 2018, W3 Engineers Ltd. All rights reserved. 6 | */ 7 | public class EntityManager { 8 | 9 | public void persist(Customer customer) { 10 | } 11 | 12 | public void flush() { 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/InitialContext.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial; 2 | 3 | public class InitialContext { 4 | 5 | public Object lookup(String serviceName) { 6 | if (serviceName.equalsIgnoreCase("EmailService")) { 7 | return new EmailService(); 8 | } else if (serviceName.equalsIgnoreCase("SMSService")) { 9 | return new SMSService(); 10 | } 11 | return null; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/exercise/eventbus/UserDetailsChangedEvent.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial.exercise.eventbus; 2 | 3 | import com.anjan.mockitounittesttutorial.exercise.users.User; 4 | 5 | 6 | public class UserDetailsChangedEvent { 7 | 8 | private final User mUser; 9 | 10 | public UserDetailsChangedEvent(User user) { 11 | mUser = user; 12 | } 13 | 14 | 15 | 16 | public User getUser() { 17 | return mUser; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/Cache.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class Cache { 7 | 8 | private List services = new ArrayList<>(); 9 | 10 | public MessagingService getService(String serviceName) { 11 | // retrieve from the list 12 | return new EmailService(); 13 | } 14 | 15 | public void addService(MessagingService newService) { 16 | // add to the list 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/exercise/users/User.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial.exercise.users; 2 | 3 | public class User { 4 | private final String mUserId; 5 | private final String mUsername; 6 | 7 | public User(String userId, String username) { 8 | mUserId = userId; 9 | mUsername = username; 10 | } 11 | 12 | public String getUserId() { 13 | return mUserId; 14 | } 15 | 16 | public String getUsername() { 17 | return mUsername; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/Point.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial; 2 | 3 | /** 4 | * Created by Anjan Debnath on 5/22/2018. 5 | * Copyright (c) 2018, W3 Engineers Ltd. All rights reserved. 6 | */ 7 | public class Point { 8 | private int x; 9 | private int y; 10 | 11 | public Point(int x, int y) { 12 | this.x = x; 13 | this.y = y; 14 | } 15 | 16 | public int getX() { 17 | return x; 18 | } 19 | 20 | public int getY() { 21 | return y; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/Utils.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial; 2 | 3 | import java.util.Random; 4 | 5 | /** 6 | * Created by Anjan Debnath on 5/22/2018. 7 | * Copyright (c) 2018, W3 Engineers Ltd. All rights reserved. 8 | */ 9 | public class Utils { 10 | private static final Random RAND = new Random(); 11 | 12 | private Utils() { 13 | // Utilities class 14 | } 15 | 16 | public static int randomDistance(int distance) { 17 | return RAND.nextInt(distance + distance) - distance; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/LocatorService.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial; 2 | 3 | /** 4 | * Created by Anjan Debnath on 5/22/2018. 5 | * Copyright (c) 2018, W3 Engineers Ltd. All rights reserved. 6 | */ 7 | public class LocatorService { 8 | public Point geoLocate(Point point) { 9 | return new Point(point.getX(), point.getY()); 10 | } 11 | 12 | public Point generatePointWithinDistance(Point point, int distance) { 13 | return new Point(point.getX() + Utils.randomDistance(distance), point.getY() + Utils.randomDistance(distance)); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/exercise/description.txt: -------------------------------------------------------------------------------- 1 | Description: 2 | Your goal is to find all bugs in UpdateUsernameUseCaseSync class without looking at its internal 3 | implementation. 4 | You should: 5 | 1) Open the test class and set up system under test (SUT). 6 | 2) Implement the required test doubles with Mockito. 7 | 3) Think about the required test cases and list them as comments. 8 | 4) Write actual tests and identify which requirements aren't satisfied. 9 | 5) Read tests output and try to come up with a hypothesis about the production code. 10 | 6) Fix the production code. 11 | 7) Make sure that all tests pass. -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/stub/CustomerReader.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial.stub; 2 | 3 | /** 4 | * Created by Anjan Debnath on 7/25/2018. 5 | * Copyright (c) 2018, W3 Engineers Ltd. All rights reserved. 6 | */ 7 | 8 | public class CustomerReader { 9 | 10 | private DbManager mDbManager; 11 | 12 | public CustomerReader(DbManager dbManager) { 13 | this.mDbManager = dbManager; 14 | } 15 | 16 | public String findName(Long customerID){ 17 | Customer customer = mDbManager.findCustomer(customerID); 18 | return customer.getFirstName() +" "+customer.getLastName(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/ServiceLocator.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial; 2 | 3 | public class ServiceLocator { 4 | 5 | private static Cache cache = new Cache(); 6 | 7 | public static MessagingService getService(String serviceName) { 8 | 9 | MessagingService service = cache.getService(serviceName); 10 | 11 | if (service != null) { 12 | return service; 13 | } 14 | 15 | InitialContext context = new InitialContext(); 16 | MessagingService service1 = (MessagingService) context 17 | .lookup(serviceName); 18 | cache.addService(service1); 19 | return service1; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | import android.os.Bundle; 5 | 6 | public class MainActivity extends AppCompatActivity { 7 | 8 | @Override 9 | protected void onCreate(Bundle savedInstanceState) { 10 | super.onCreate(savedInstanceState); 11 | setContentView(R.layout.activity_main); 12 | } 13 | 14 | /** 15 | * Gets the unique id. 16 | * 17 | * @return the unique id 18 | */ 19 | public int getUniqueId() { 20 | return 43; 21 | } 22 | 23 | public int testing(int num) { 24 | someMethod(""); 25 | return num; 26 | } 27 | 28 | public void someMethod(String someMethod) { 29 | testing(1); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 21 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/anjan/mockitounittesttutorial/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.anjan.mockitounittesttutorial", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/async/DummyCollaborator.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial.async; 2 | 3 | import java.util.Collections; 4 | 5 | /** 6 | * Created by Anjan Debnath on 7/23/2018. 7 | * Copyright (c) 2018, W3 Engineers Ltd. All rights reserved. 8 | */ 9 | public class DummyCollaborator { 10 | public static int ERROR_CODE = 1; 11 | 12 | public DummyCollaborator() { 13 | 14 | } 15 | 16 | public void doSomethingAsynchronously(final DummyCallback callback){ 17 | new Thread(new Runnable() { 18 | @Override 19 | public void run() { 20 | 21 | try { 22 | Thread.sleep(5000); 23 | callback.onSuccess(Collections.EMPTY_LIST); 24 | } catch (InterruptedException e) { 25 | callback.onFail(ERROR_CODE); 26 | e.printStackTrace(); 27 | } 28 | } 29 | }).start(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/mock/Customer.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial.mock; 2 | 3 | /** 4 | * Created by Anjan Debnath on 7/25/2018. 5 | * Copyright (c) 2018, W3 Engineers Ltd. All rights reserved. 6 | */ 7 | public class Customer { 8 | 9 | private long id; 10 | 11 | private String firstName; 12 | 13 | private String lastName; 14 | 15 | public Customer(String firstName, String lastName) { 16 | this.firstName = firstName; 17 | this.lastName = lastName; 18 | } 19 | 20 | public long getId() { 21 | return id; 22 | } 23 | 24 | public void setId(long id) { 25 | this.id = id; 26 | } 27 | 28 | public String getFirstName() { 29 | return firstName; 30 | } 31 | 32 | public void setFirstName(String firstName) { 33 | this.firstName = firstName; 34 | } 35 | 36 | public String getLastName() { 37 | return lastName; 38 | } 39 | 40 | public void setLastName(String lastName) { 41 | this.lastName = lastName; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | 12 | ## I'm submitting a ... 13 | 14 | - [ ] feature request 15 | - [ ] support request 16 | 17 | ## Expected Behavior 18 | 19 | 20 | ## Actual Behavior 21 | 22 | 23 | 24 | ## What is the motivation / use case for changing the behavior? 25 | 26 | 27 | 28 | ## Your Environment 29 | 30 | * App version used: 31 | * Device Name and version: 32 | * Operating System and version: 33 | 34 | 35 | * **Other information** (e.g. detailed explanation, stacktraces, related issues, suggestions how to fix, links for us to have context, eg. stackoverflow, gitter, etc) 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/async/DummyCaller.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial.async; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * Created by Anjan Debnath on 7/23/2018. 8 | * Copyright (c) 2018, W3 Engineers Ltd. All rights reserved. 9 | */ 10 | public class DummyCaller implements DummyCallback{ 11 | 12 | DummyCollaborator dummyCollaborator; 13 | 14 | private List result = new ArrayList(); 15 | 16 | public DummyCaller(DummyCollaborator dummyCollaborator){ 17 | this.dummyCollaborator = dummyCollaborator; 18 | } 19 | 20 | public void doSomethingAsynchronously(){ 21 | dummyCollaborator.doSomethingAsynchronously(this); 22 | } 23 | 24 | public List getResult(){ 25 | return this.result; 26 | } 27 | 28 | @Override 29 | public void onSuccess(List result) { 30 | this.result = result; 31 | System.out.println("On success"); 32 | } 33 | 34 | @Override 35 | public void onFail(int code) { 36 | System.out.println("On Fail"); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | 12 | ## Description 13 | 14 | 15 | ## Expected Behavior 16 | 17 | 18 | ## Actual Behavior 19 | 20 | 21 | ## Possible Fix 22 | 23 | 24 | ## Steps to Reproduce 25 | 26 | 27 | 1. 28 | 2. 29 | 3. 30 | 4. 31 | 32 | ## Context 33 | 34 | 35 | ## Your Environment 36 | 37 | * App version used: 38 | * Device Name and version: 39 | * Operating System and version: 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/stub/Customer.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial.stub; 2 | 3 | /** 4 | * Created by Anjan Debnath on 7/25/2018. 5 | * Copyright (c) 2018, W3 Engineers Ltd. All rights reserved. 6 | */ 7 | 8 | public class Customer { 9 | 10 | /** 11 | * DataStructure 12 | * Expose data 13 | * No behaviour 14 | * Can be instantiated with other Objects 15 | * No need to be substituted with test doubles 16 | */ 17 | 18 | private long id; 19 | 20 | private String firstName; 21 | 22 | private String lastName; 23 | 24 | public long getId() { 25 | return id; 26 | } 27 | 28 | public void setId(long id) { 29 | this.id = id; 30 | } 31 | 32 | public String getFirstName() { 33 | return firstName; 34 | } 35 | 36 | public void setFirstName(String firstName) { 37 | this.firstName = firstName; 38 | } 39 | 40 | public String getLastName() { 41 | return lastName; 42 | } 43 | 44 | public void setLastName(String lastName) { 45 | this.lastName = lastName; 46 | } 47 | 48 | 49 | 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/contributor/ContributorActivity.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial.contributor; 2 | 3 | 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.util.Log; 8 | 9 | import com.anjan.mockitounittesttutorial.R; 10 | 11 | public class ContributorActivity extends AppCompatActivity { 12 | 13 | @Override 14 | public void onCreate(@Nullable Bundle savedInstanceState) { 15 | super.onCreate(savedInstanceState); 16 | setContentView(R.layout.activity_main); 17 | } 18 | 19 | @Override 20 | protected void onResume() { 21 | super.onResume(); 22 | } 23 | 24 | @Override 25 | protected void onPause() { 26 | super.onPause(); 27 | } 28 | 29 | 30 | public void methodCreatedByOwner() { 31 | 32 | Log.d("Owner", "This method has created by owner"); 33 | } 34 | public void methodCreatedByContributor(){ 35 | 36 | Log.d("Owner", "This method has created by contributor machine"); 37 | 38 | Log.d("Pull request", "change log test"); 39 | 40 | } 41 | } 42 | 43 | 44 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/mock/LateInvoiceNotifier.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial.mock; 2 | 3 | import android.annotation.SuppressLint; 4 | 5 | import java.time.LocalDate; 6 | 7 | /** 8 | * Created by Anjan Debnath on 7/25/2018. 9 | * Copyright (c) 2018, W3 Engineers Ltd. All rights reserved. 10 | */ 11 | public class LateInvoiceNotifier { 12 | 13 | private final EmailSender emailSender; 14 | private final InvoiceStorage invoiceStorage; 15 | private final EventRecorder eventRecorder; 16 | 17 | private static final String NAME = "Susan Ivanova"; 18 | 19 | 20 | public LateInvoiceNotifier(final EmailSender emailSender, final InvoiceStorage invoiceStorage, EventRecorder eventRecorder){ 21 | this.emailSender = emailSender; 22 | this.invoiceStorage = invoiceStorage; 23 | this.eventRecorder = eventRecorder; 24 | } 25 | 26 | @SuppressLint("NewApi") 27 | public void notifyLate(Customer customer){ 28 | if(invoiceStorage.hasOutstandingInvoice(customer)){ 29 | eventRecorder.recordEvent(new Event(Event.Type.REMINDER_SENT, NAME, LocalDate.now())); 30 | emailSender.sendEmail(customer); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/stub/DbManager.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial.stub; 2 | 3 | /** 4 | * Created by Anjan Debnath on 7/25/2018. 5 | * Copyright (c) 2018, W3 Engineers Ltd. All rights reserved. 6 | */ 7 | 8 | public class DbManager { 9 | 10 | public static final String FIRST_NAME = "Customer"; 11 | public static final String LAST_NAME = "Name"; 12 | 13 | /** 14 | * Object 15 | * Expose behaviours 16 | * Hide internal implementation detail 17 | * Should be injected into other Objects 18 | * Need to be unit tested explicitly 19 | * Eligible to be substituted with test doubles 20 | */ 21 | 22 | public Customer findCustomer(Long customerId){ 23 | Customer customer = null; 24 | if(customerId > 0){ 25 | customer = new Customer(); 26 | /** 27 | * here will be the database fetch code 28 | * and from that fetched value we will get the 29 | * customer. 30 | */ 31 | customer.setId(customerId); 32 | customer.setFirstName(FIRST_NAME); 33 | customer.setLastName(LAST_NAME); 34 | } 35 | return customer; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/mock/Event.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial.mock; 2 | 3 | import java.time.LocalDate; 4 | 5 | /** 6 | * Created by Anjan Debnath on 7/25/2018. 7 | * Copyright (c) 2018, W3 Engineers Ltd. All rights reserved. 8 | */ 9 | public class Event { 10 | 11 | public enum Type {REMINDER_SENT, REGISTRATION, INVOICE_ISSUED,PAYMENT, SETTLEMENT}; 12 | 13 | public Type getType() { 14 | return type; 15 | } 16 | 17 | public void setType(Type type) { 18 | this.type = type; 19 | } 20 | 21 | public String getCustomerName() { 22 | return customerName; 23 | } 24 | 25 | public void setCustomerName(String customerName) { 26 | this.customerName = customerName; 27 | } 28 | 29 | public LocalDate getTimestamp() { 30 | return timestamp; 31 | } 32 | 33 | public void setTimestamp(LocalDate timestamp) { 34 | this.timestamp = timestamp; 35 | } 36 | 37 | private Type type; 38 | private String customerName; 39 | private LocalDate timestamp; 40 | 41 | Event(Type type, String customerName, LocalDate timestamp){ 42 | this.type = type; 43 | this.customerName = customerName; 44 | this.timestamp = timestamp; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/sync/networking/LoginHttpEndpointSync.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial.sync.networking; 2 | 3 | /** 4 | * Created by Anjan Debnath on 7/23/2018. 5 | * Copyright (c) 2018, W3 Engineers Ltd. All rights reserved. 6 | */ 7 | public interface LoginHttpEndpointSync { 8 | 9 | /** 10 | * Log in using provided credentials 11 | * @return the aggregated result of login operation 12 | * @throws NetworkErrorException if login attempt failed due to network error 13 | */ 14 | EndpointResult loginSync(String username, String password) throws NetworkErrorException; 15 | 16 | enum EndpointResultStatus { 17 | SUCCESS, 18 | AUTH_ERROR, 19 | SERVER_ERROR, 20 | GENERAL_ERROR 21 | } 22 | 23 | class EndpointResult { 24 | private final EndpointResultStatus mStatus; 25 | private final String mAuthToken; 26 | 27 | public EndpointResult(EndpointResultStatus status, String authToken) { 28 | mStatus = status; 29 | mAuthToken = authToken; 30 | } 31 | 32 | public EndpointResultStatus getStatus() { 33 | return mStatus; 34 | } 35 | 36 | public String getAuthToken() { 37 | return mAuthToken; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/exercise/networking/UpdateUsernameHttpEndpointSync.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial.exercise.networking; 2 | 3 | public interface UpdateUsernameHttpEndpointSync { 4 | 5 | /** 6 | * Update user's username on the server 7 | * @return the aggregated result 8 | * @throws NetworkErrorException if operation failed due to network error 9 | */ 10 | EndpointResult updateUsername(String userId, String username) throws NetworkErrorException; 11 | 12 | enum EndpointResultStatus { 13 | SUCCESS, 14 | AUTH_ERROR, 15 | SERVER_ERROR, 16 | GENERAL_ERROR 17 | } 18 | 19 | class EndpointResult { 20 | private final EndpointResultStatus mStatus; 21 | private final String mUserId; 22 | private final String mUsername; 23 | 24 | public EndpointResult(EndpointResultStatus status, String userId, String username) { 25 | mStatus = status; 26 | mUserId = userId; 27 | mUsername = username; 28 | } 29 | 30 | public EndpointResultStatus getStatus() { 31 | return mStatus; 32 | } 33 | 34 | public String getUserId() { 35 | return mUserId; 36 | } 37 | 38 | public String getUsername() { 39 | return mUserId; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change. 4 | 5 | Fixes # (issue) 6 | 7 | ## Type of change 8 | 9 | Please delete options that are not relevant. 10 | 11 | - [ ] Bug fix (non-breaking change which fixes an issue) 12 | - [ ] New feature (non-breaking change which adds functionality) 13 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 14 | - [ ] This change requires a documentation update 15 | 16 | ## How Has This Been Tested? 17 | 18 | Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration 19 | 20 | - [ ] Test A 21 | - [ ] Test B 22 | 23 | **Test Configuration**: 24 | * Firmware version: 25 | * Hardware: 26 | * Toolchain: 27 | * SDK: 28 | 29 | ## Checklist: 30 | 31 | - [ ] My code follows the style guidelines of this project 32 | - [ ] I have performed a self-review of my own code 33 | - [ ] I have commented my code, particularly in hard-to-understand areas 34 | - [ ] I have made corresponding changes to the documentation 35 | - [ ] My changes generate no new warnings 36 | - [ ] I have added tests that prove my fix is effective or that my feature works 37 | - [ ] New and existing unit tests pass locally with my changes 38 | - [ ] Any dependent changes have been merged and published in downstream modules -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 27 5 | defaultConfig { 6 | applicationId "com.anjan.mockitounittesttutorial" 7 | minSdkVersion 15 8 | targetSdkVersion 27 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | compileOptions { 20 | sourceCompatibility JavaVersion.VERSION_1_8 21 | targetCompatibility JavaVersion.VERSION_1_8 22 | } 23 | } 24 | 25 | dependencies { 26 | implementation fileTree(include: ['*.jar'], dir: 'libs') 27 | implementation 'com.android.support:appcompat-v7:27.1.1' 28 | implementation 'com.android.support.constraint:constraint-layout:1.1.0' 29 | testImplementation 'junit:junit:4.12' 30 | // required if you want to use Mockito for unit tests 31 | testImplementation 'org.mockito:mockito-core:2.7.22' 32 | // required if you want to use Mockito for Android tests 33 | androidTestImplementation 'org.mockito:mockito-android:2.7.22' 34 | // required if you want to use Hamcrest matching 35 | testImplementation 'org.hamcrest:hamcrest-library:1.3' 36 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 37 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 38 | } 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | *.aab 5 | 6 | # Files for the ART/Dalvik VM 7 | *.dex 8 | 9 | # Java class files 10 | *.class 11 | 12 | # Generated files 13 | bin/ 14 | gen/ 15 | out/ 16 | release/ 17 | 18 | # Gradle files 19 | .gradle/ 20 | build/ 21 | 22 | # Local configuration file (sdk path, etc) 23 | local.properties 24 | 25 | # Proguard folder generated by Eclipse 26 | proguard/ 27 | 28 | # Log Files 29 | *.log 30 | 31 | # Android Studio Navigation editor temp files 32 | .navigation/ 33 | 34 | # Android Studio captures folder 35 | captures/ 36 | 37 | # IntelliJ 38 | *.iml 39 | .idea/workspace.xml 40 | .idea/tasks.xml 41 | .idea/gradle.xml 42 | .idea/assetWizardSettings.xml 43 | .idea/dictionaries 44 | .idea/libraries 45 | # Android Studio 3 in .gitignore file. 46 | .idea/caches 47 | .idea/modules.xml 48 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you 49 | .idea/navEditor.xml 50 | 51 | # Keystore files 52 | # Uncomment the following lines if you do not want to check your keystore files in. 53 | #*.jks 54 | #*.keystore 55 | 56 | # External native build folder generated in Android Studio 2.2 and later 57 | .externalNativeBuild 58 | 59 | # Google Services (e.g. APIs or Firebase) 60 | # google-services.json 61 | 62 | # Freeline 63 | freeline.py 64 | freeline/ 65 | freeline_project_description.json 66 | 67 | # fastlane 68 | fastlane/report.xml 69 | fastlane/Preview.html 70 | fastlane/screenshots 71 | fastlane/test_output 72 | fastlane/readme.md 73 | 74 | # Version control 75 | vcs.xml 76 | 77 | # lint 78 | lint/intermediates/ 79 | lint/generated/ 80 | lint/outputs/ 81 | lint/tmp/ 82 | # lint/reports/ 83 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/async/db/CustomerDao.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial.async.db; 2 | 3 | import com.anjan.mockitounittesttutorial.mock.Customer; 4 | 5 | /** 6 | * Created by Anjan Debnath on 8/6/2018. 7 | * Copyright (c) 2018, W3 Engineers Ltd. All rights reserved. 8 | */ 9 | public class CustomerDao { 10 | 11 | private EntityManager entityManager; 12 | 13 | private Logger logger; 14 | 15 | public CustomerDao(EntityManager entityManager, Logger logger){ 16 | this.entityManager = entityManager; 17 | this.logger = logger; 18 | } 19 | 20 | /** 21 | * once the customer is saved using the persist method, its database ID is sent to the logger. 22 | * For this contrived example, the code will work just fine in the real system, as the database 23 | * will indeed assign an ID to the object as soon as it is saved. 24 | * But how can we replicate this processing in our unit test? 25 | * The persist method does not return an argument so we cannot mock it with the usual when/then directives. 26 | * However, even for this corner case, Mockito still has a solution: 27 | * @param firstName 28 | * @param lastName 29 | */ 30 | public void saveCustomer(String firstName, String lastName) { 31 | if(firstName == null || lastName==null) 32 | { 33 | logger.error("Missing customer information"); 34 | throw new IllegalArgumentException(); 35 | } 36 | Customer customer = new Customer(firstName,lastName); 37 | entityManager.persist(customer); 38 | entityManager.flush(); 39 | logger.info("Saved customer with id {}", customer.getId()); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 27 | 28 | 29 | 30 | 31 | 32 | 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/Locator.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial; 2 | 3 | 4 | import android.util.Log; 5 | 6 | /** 7 | * Created by Anjan Debnath on 5/22/2018. 8 | * Copyright (c) 2018, W3 Engineers Ltd. All rights reserved. 9 | */ 10 | public class Locator { 11 | private final LocatorService locatorService; 12 | 13 | private static Cache cache = new Cache(); 14 | 15 | public Locator(LocatorService locatorService) { 16 | this.locatorService = locatorService; 17 | } 18 | 19 | public Point locate(int x, int y) { 20 | if (x < 0 || y < 0) { 21 | return new Point(Math.abs(x), Math.abs(y)); 22 | } else { 23 | return locatorService.geoLocate(new Point(x, y)); 24 | } 25 | } 26 | 27 | 28 | public static MessagingService getService(String serviceName) { 29 | 30 | 31 | MessagingService service = cache.getService(serviceName); 32 | 33 | if (service != null) { 34 | return service; 35 | } 36 | 37 | InitialContext context = new InitialContext(); 38 | MessagingService service1 = (MessagingService) context 39 | .lookup(serviceName); 40 | cache.addService(service1); 41 | return service1; 42 | } 43 | 44 | private void LocationTracker(Point point){ 45 | 46 | MessagingService service 47 | = ServiceLocator.getService("EmailService"); 48 | String email = service.getMessageBody(); 49 | 50 | MessagingService smsService 51 | = ServiceLocator.getService("SMSService"); 52 | String sms = smsService.getMessageBody(); 53 | } 54 | 55 | private void fixIssueFive(){ 56 | Log.e("TAG", "Fix the issue no 5"); 57 | 58 | if(locatorService!= null){ 59 | Point p = new Point(22, 34); 60 | locatorService.geoLocate(p); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /app/src/test/java/com/anjan/mockitounittesttutorial/stub/CustomerReaderTest.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial.stub; 2 | 3 | import org.junit.Before; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | 7 | import org.mockito.Mock; 8 | import org.mockito.junit.MockitoJUnitRunner; 9 | 10 | import static org.hamcrest.CoreMatchers.equalTo; 11 | import static org.hamcrest.CoreMatchers.is; 12 | import static org.junit.Assert.assertThat; 13 | import static org.mockito.Mockito.when; 14 | 15 | 16 | /** 17 | * Created by Anjan Debnath on 7/25/2018. 18 | * Copyright (c) 2018, W3 Engineers Ltd. All rights reserved. 19 | */ 20 | @RunWith(MockitoJUnitRunner.class) 21 | public class CustomerReaderTest { 22 | 23 | //region constants 24 | private static final long CUSTOMER_ID = 1L; 25 | private static final String CUSTOMER_NAME = "customer Name"; 26 | public static final String FIRST_NAME = "Customer"; 27 | public static final String LAST_NAME = "Name"; 28 | //endregion constants 29 | 30 | //region helper fields 31 | @Mock 32 | DbManager dbManagerMock; 33 | //endregion helper fields 34 | 35 | CustomerReader SUT; 36 | 37 | @Before 38 | public void setup() throws Exception { 39 | 40 | SUT = new CustomerReader(dbManagerMock); 41 | 42 | } 43 | 44 | @Test 45 | public void test_customerIdPassed_nameReturned() { 46 | 47 | //arrange 48 | Customer customer = new Customer(); 49 | customer.setFirstName(FIRST_NAME); 50 | customer.setLastName(LAST_NAME); 51 | when(dbManagerMock.findCustomer(CUSTOMER_ID)).thenReturn(customer); 52 | //action 53 | String name = SUT.findName(CUSTOMER_ID); 54 | //assert 55 | assertThat(name, is(equalTo(CUSTOMER_NAME))); 56 | } 57 | 58 | 59 | //region helper methods 60 | 61 | //endregion helper methods 62 | 63 | //region helper classes 64 | 65 | //endregion helper classes 66 | 67 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/test/java/com/anjan/mockitounittesttutorial/async/db/CustomerDaoTest.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial.async.db; 2 | 3 | import com.anjan.mockitounittesttutorial.mock.Customer; 4 | 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | import org.junit.runner.RunWith; 8 | import org.mockito.Mock; 9 | import org.mockito.invocation.InvocationOnMock; 10 | import org.mockito.junit.MockitoJUnitRunner; 11 | import org.mockito.stubbing.Answer; 12 | 13 | import static org.mockito.ArgumentMatchers.any; 14 | import static org.mockito.Mockito.doAnswer; 15 | import static org.mockito.Mockito.verify; 16 | 17 | 18 | /** 19 | * Created by Anjan Debnath on 8/6/2018. 20 | * Copyright (c) 2018, W3 Engineers Ltd. All rights reserved. 21 | */ 22 | @RunWith(MockitoJUnitRunner.class) 23 | public class CustomerDaoTest { 24 | public static final String JOHN = "John"; 25 | public static final String DOUVER = "Douver"; 26 | 27 | //region constants 28 | 29 | //endregion constants 30 | 31 | //region helper fields 32 | @Mock 33 | EntityManager entityManagerMock; 34 | @Mock 35 | Logger loggerMock; 36 | //endregion helper fields 37 | 38 | private CustomerDao SUT; 39 | 40 | @Before 41 | public void setup() throws Exception { 42 | 43 | SUT = new CustomerDao(entityManagerMock,loggerMock); 44 | 45 | } 46 | 47 | @Test 48 | public void dao_whenCustomerSaved_returnedCustomerId() { 49 | 50 | //arrange 51 | doAnswer(new Answer() { 52 | @Override 53 | public Object answer(InvocationOnMock invocation) throws Throwable { 54 | Customer customer = (Customer) invocation.getArguments()[0]; 55 | customer.setId(123L); 56 | return null; 57 | } 58 | }).when(entityManagerMock).persist(any(Customer.class)); 59 | 60 | //action 61 | SUT.saveCustomer(JOHN, DOUVER); 62 | //assert 63 | verify(loggerMock).info("Saved customer with id {}", 123L); 64 | 65 | } 66 | 67 | //region helper methods 68 | 69 | //endregion helper methods 70 | 71 | //region helper classes 72 | 73 | //endregion helper classes 74 | 75 | } -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/sync/LoginUseCaseSync.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial.sync; 2 | 3 | 4 | import com.anjan.mockitounittesttutorial.sync.authtoken.AuthTokenCache; 5 | import com.anjan.mockitounittesttutorial.sync.eventbus.EventBusPoster; 6 | import com.anjan.mockitounittesttutorial.sync.eventbus.LoggedInEvent; 7 | import com.anjan.mockitounittesttutorial.sync.networking.LoginHttpEndpointSync; 8 | import com.anjan.mockitounittesttutorial.sync.networking.NetworkErrorException; 9 | 10 | /** 11 | * Created by Anjan Debnath on 7/23/2018. 12 | * Copyright (c) 2018, W3 Engineers Ltd. All rights reserved. 13 | */ 14 | 15 | public class LoginUseCaseSync { 16 | 17 | public enum UseCaseResult { 18 | SUCCESS, 19 | FAILURE, 20 | NETWORK_ERROR 21 | } 22 | 23 | /** 24 | * Collaborators 25 | */ 26 | private final LoginHttpEndpointSync mLoginHttpEndpointSync; 27 | private final AuthTokenCache mAuthTokenCache; 28 | private final EventBusPoster mEventBusPoster; 29 | 30 | public LoginUseCaseSync(LoginHttpEndpointSync loginHttpEndpointSync, 31 | AuthTokenCache authTokenCache, 32 | EventBusPoster eventBusPoster) { 33 | mLoginHttpEndpointSync = loginHttpEndpointSync; 34 | mAuthTokenCache = authTokenCache; 35 | mEventBusPoster = eventBusPoster; 36 | } 37 | 38 | public UseCaseResult loginSync(String username, String password) { 39 | LoginHttpEndpointSync.EndpointResult endpointEndpointResult; 40 | try { 41 | endpointEndpointResult = mLoginHttpEndpointSync.loginSync(username, password); 42 | } catch (NetworkErrorException e) { 43 | return UseCaseResult.NETWORK_ERROR; 44 | } 45 | 46 | if (isSuccessfulEndpointResult(endpointEndpointResult)) { 47 | mAuthTokenCache.cacheAuthToken(endpointEndpointResult.getAuthToken()); 48 | mEventBusPoster.postEvent(new LoggedInEvent()); 49 | return UseCaseResult.SUCCESS; 50 | } else { 51 | return UseCaseResult.FAILURE; 52 | } 53 | } 54 | 55 | private boolean isSuccessfulEndpointResult(LoginHttpEndpointSync.EndpointResult endpointResult) { 56 | return endpointResult.getStatus() == LoginHttpEndpointSync.EndpointResultStatus.SUCCESS; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /app/src/main/java/com/anjan/mockitounittesttutorial/exercise/UpdateUsernameUseCaseSync.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial.exercise; 2 | 3 | 4 | import com.anjan.mockitounittesttutorial.exercise.eventbus.EventBusPoster; 5 | import com.anjan.mockitounittesttutorial.exercise.eventbus.UserDetailsChangedEvent; 6 | import com.anjan.mockitounittesttutorial.exercise.networking.NetworkErrorException; 7 | import com.anjan.mockitounittesttutorial.exercise.networking.UpdateUsernameHttpEndpointSync; 8 | import com.anjan.mockitounittesttutorial.exercise.users.User; 9 | import com.anjan.mockitounittesttutorial.exercise.users.UsersCache; 10 | 11 | public class UpdateUsernameUseCaseSync { 12 | 13 | public enum UseCaseResult { 14 | SUCCESS, 15 | FAILURE, 16 | NETWORK_ERROR 17 | } 18 | 19 | private final UpdateUsernameHttpEndpointSync mUpdateUsernameHttpEndpointSync; 20 | private final UsersCache mUsersCache; 21 | private final EventBusPoster mEventBusPoster; 22 | 23 | public UpdateUsernameUseCaseSync(UpdateUsernameHttpEndpointSync updateUsernameHttpEndpointSync, 24 | UsersCache usersCache, 25 | EventBusPoster eventBusPoster) { 26 | mUpdateUsernameHttpEndpointSync = updateUsernameHttpEndpointSync; 27 | mUsersCache = usersCache; 28 | mEventBusPoster = eventBusPoster; 29 | } 30 | 31 | public UseCaseResult updateUsernameSync(String userId, String username) { 32 | UpdateUsernameHttpEndpointSync.EndpointResult endpointResult = null; 33 | try { 34 | endpointResult = mUpdateUsernameHttpEndpointSync.updateUsername(userId, username); 35 | } catch (NetworkErrorException e) { 36 | // the bug here is "swallowed" exception instead of return 37 | } 38 | 39 | if (isSuccessfulEndpointResult(endpointResult)) { 40 | // the bug here is reversed arguments 41 | User user = new User(endpointResult.getUsername(), endpointResult.getUserId()); 42 | mEventBusPoster.postEvent(new UserDetailsChangedEvent(new User(userId, username))); 43 | mUsersCache.cacheUser(user); 44 | return UseCaseResult.SUCCESS; 45 | } else { 46 | return UseCaseResult.FAILURE; 47 | } 48 | } 49 | 50 | private boolean isSuccessfulEndpointResult(UpdateUsernameHttpEndpointSync.EndpointResult endpointResult) { 51 | // the bug here is the wrong definition of successful response 52 | return endpointResult.getStatus() == UpdateUsernameHttpEndpointSync.EndpointResultStatus.SUCCESS 53 | || endpointResult.getStatus() == UpdateUsernameHttpEndpointSync.EndpointResultStatus.GENERAL_ERROR; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/src/test/java/com/anjan/mockitounittesttutorial/LocatorTest.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial; 2 | 3 | import org.junit.Before; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.mockito.ArgumentCaptor; 7 | import org.mockito.Mock; 8 | import org.mockito.junit.MockitoJUnitRunner; 9 | 10 | import static org.hamcrest.CoreMatchers.equalTo; 11 | import static org.hamcrest.CoreMatchers.is; 12 | import static org.junit.Assert.assertThat; 13 | import static org.mockito.ArgumentMatchers.any; 14 | import static org.mockito.Mockito.verify; 15 | import static org.mockito.Mockito.when; 16 | 17 | 18 | /** 19 | * Created by Anjan Debnath on 7/24/2018. 20 | * Copyright (c) 2018, W3 Engineers Ltd. All rights reserved. 21 | */ 22 | @RunWith(MockitoJUnitRunner.class) 23 | public class LocatorTest { 24 | 25 | //region constants 26 | public static final int POINT_X = 1; 27 | public static final int POINT_Y = 1; 28 | //endregion constants 29 | 30 | //region helper fields 31 | 32 | //endregion helper fields 33 | Locator SUT; 34 | @Mock 35 | LocatorService locatorServiceMock; 36 | 37 | @Before 38 | public void setup() throws Exception { 39 | 40 | SUT = new Locator(locatorServiceMock); 41 | 42 | } 43 | 44 | //region readme 45 | /** 46 | * we will use Argument Captor AC to verify mock object. 47 | * Assert must be called after any verify with AC. 48 | */ 49 | //endregion readme 50 | @Test 51 | public void locator_passPositiveValueToLocatorService_success() { 52 | ArgumentCaptor pointAc = ArgumentCaptor.forClass(Point.class); 53 | SUT.locate(POINT_X, POINT_Y); 54 | verify(locatorServiceMock).geoLocate(pointAc.capture()); 55 | Point point = pointAc.getValue(); 56 | assertThat(point.getX(), is(equalTo(POINT_X))); 57 | assertThat(point.getY(), is(equalTo(POINT_Y))); 58 | } 59 | 60 | @Test 61 | public void locator_passNegativeValue_positiveReturn() { 62 | 63 | Point point = SUT.locate(-1, -1); 64 | assertThat(point.getX(), is(POINT_X)); 65 | } 66 | 67 | 68 | //region readme 69 | /** 70 | * when the test class's method return any result 71 | * that is dependent to the mock object then that 72 | * mock object should be stubbed. 73 | */ 74 | //endregion readme 75 | @Test 76 | public void locator_positiveValue_returnPointSuccess() { 77 | 78 | //Stubbing locator service 79 | when(locatorServiceMock.geoLocate(any(Point.class))).thenReturn(new Point(POINT_X, POINT_Y)); 80 | 81 | Point point = SUT.locate(POINT_X, POINT_Y); 82 | assertThat(point.getX(), is(POINT_X)); 83 | 84 | } 85 | 86 | //region helper methods 87 | 88 | //endregion helper methods 89 | 90 | //region helper classes 91 | 92 | //endregion helper classes 93 | 94 | } -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Unit test with Mockito 2 | 3 | *Ackwoledgement* : This Project is created for getting familiar with Mockito JUnit test. 4 | This repository is created by taking reference from following links: 5 | 6 | - https://automationrhapsody.com/mock-junit-tests-mockito-example/ 7 | - https://semaphoreci.com/community/tutorials/stubbing-and-mocking-with-mockito-2-and-junit 8 | - https://hackernoon.com/objects-vs-data-structures-e380b962c1d2 9 | - https://stackoverflow.com/questions/36253040/example-on-mockitos-argumentcaptor 10 | - https://javacodehouse.com/blog/junit-tutorial/ 11 | - http://www.baeldung.com/mockito-annotations 12 | - https://javacodehouse.com/blog/mockito-tutorial/ 13 | 14 | 15 | 16 | ## Custom template create for Junit4 17 | 18 | From Android studio go to In the top menu, go to `file > Settings` 19 | and in the settings. In the left menu, find `Editor > File and Code templates` and click on the `Code Tab` 20 | and find `Junit4 Test Class`. 21 | 22 | ![see here](https://github.com/anjandebnath/MockitoUnitTestTutorial/blob/master/AS.PNG) 23 | 24 | 25 | - Now its time to create a custom template for unit test 26 | - Just copy and paste this and get some pre defined imports and methods. 27 | 28 | ```` 29 | import org.junit.After; 30 | import org.junit.AfterClass; 31 | import org.junit.Before; 32 | import org.junit.BeforeClass; 33 | import org.junit.Test; 34 | import org.junit.runner.RunWith; 35 | 36 | import org.mockito.junit.MockitoJUnitRunner; 37 | import static org.mockito.Mock.*; 38 | import static org.mockito.Mockito.*; 39 | import static org.hamcrest.CoreMatchers.*; 40 | import static org.junit.Assert.*; 41 | import static org.mockito.ArgumentCaptor.*; 42 | import static org.mockito.ArgumentMatchers.*; 43 | 44 | 45 | 46 | #parse("File Header.java") 47 | @RunWith(MockitoJUnitRunner.class) 48 | public class ${NAME} { 49 | 50 | //region constants 51 | 52 | //endregion constants 53 | 54 | //region helper fields 55 | 56 | //endregion helper fields 57 | 58 | ${CLASS_NAME} SUT; 59 | 60 | @Before 61 | public void setup() throws Exception{ 62 | 63 | SUT = new ${CLASS_NAME} (); 64 | ${BODY} 65 | } 66 | 67 | //region helper methods 68 | 69 | //endregion helper methods 70 | 71 | //region helper classes 72 | 73 | //endregion helper classes 74 | 75 | } 76 | ```` 77 | 78 | 79 | ### From where you start? 80 | 81 | you will find the slides [here](https://github.com/anjandebnath/MockitoUnitTestTutorial/tree/master/slides) 82 | 83 | Find the documentation [here](https://github.com/anjandebnath/MockitoUnitTestTutorial/tree/master/assets) 84 | 85 | This will give you the basic idea about unit test. 86 | 87 | start exploring the code from this sequence 88 | 89 | under `test` package 90 | - LocatorTest 91 | - stub-> CustomerReaderTest 92 | - mock-> LateInvoiceNotifierTest 93 | - sync-> LoginUseCaseSyncTest 94 | - async-> DummyCallerTest 95 | 96 | Thanks 97 | 98 | Anjan Debnath -------------------------------------------------------------------------------- /CODE-OF-CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies within all project spaces, and it also applies when 49 | an individual is representing the project or its community in public spaces. 50 | Examples of representing a project or community include using an official 51 | project e-mail address, posting via an official social media account, or acting 52 | as an appointed representative at an online or offline event. Representation of 53 | a project may be further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at [info@telemesh.net]. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | xmlns:android 14 | 15 | ^$ 16 | 17 | 18 | 19 |
20 |
21 | 22 | 23 | 24 | xmlns:.* 25 | 26 | ^$ 27 | 28 | 29 | BY_NAME 30 | 31 |
32 |
33 | 34 | 35 | 36 | .*:id 37 | 38 | http://schemas.android.com/apk/res/android 39 | 40 | 41 | 42 |
43 |
44 | 45 | 46 | 47 | .*:name 48 | 49 | http://schemas.android.com/apk/res/android 50 | 51 | 52 | 53 |
54 |
55 | 56 | 57 | 58 | name 59 | 60 | ^$ 61 | 62 | 63 | 64 |
65 |
66 | 67 | 68 | 69 | style 70 | 71 | ^$ 72 | 73 | 74 | 75 |
76 |
77 | 78 | 79 | 80 | .* 81 | 82 | ^$ 83 | 84 | 85 | BY_NAME 86 | 87 |
88 |
89 | 90 | 91 | 92 | .* 93 | 94 | http://schemas.android.com/apk/res/android 95 | 96 | 97 | ANDROID_ATTRIBUTE_ORDER 98 | 99 |
100 |
101 | 102 | 103 | 104 | .* 105 | 106 | .* 107 | 108 | 109 | BY_NAME 110 | 111 |
112 |
113 |
114 |
115 |
116 |
-------------------------------------------------------------------------------- /app/src/test/java/com/anjan/mockitounittesttutorial/async/DummyCallerTest.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial.async; 2 | 3 | import org.junit.After; 4 | import org.junit.AfterClass; 5 | import org.junit.Before; 6 | import org.junit.BeforeClass; 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import org.mockito.ArgumentCaptor; 11 | import org.mockito.Captor; 12 | import org.mockito.Mock; 13 | import org.mockito.MockitoAnnotations; 14 | import org.mockito.invocation.InvocationOnMock; 15 | import org.mockito.junit.MockitoJUnitRunner; 16 | import org.mockito.stubbing.Answer; 17 | 18 | import java.util.Arrays; 19 | import java.util.List; 20 | 21 | import static org.hamcrest.CoreMatchers.equalTo; 22 | import static org.hamcrest.CoreMatchers.is; 23 | import static org.mockito.Mock.*; 24 | import static org.mockito.Mockito.*; 25 | import static org.junit.Assert.*; 26 | import static org.mockito.ArgumentCaptor.*; 27 | 28 | 29 | 30 | /** 31 | * Created by Anjan Debnath on 7/23/2018. 32 | * Copyright (c) 2018, W3 Engineers Ltd. All rights reserved. 33 | */ 34 | @RunWith(MockitoJUnitRunner.class) 35 | public class DummyCallerTest { 36 | 37 | //region constants 38 | 39 | //endregion constants 40 | 41 | //region helper fields 42 | @Mock 43 | private DummyCollaborator mDummyCollaboratorMock; 44 | 45 | //endregion helper fields 46 | 47 | DummyCaller SUT; 48 | 49 | @Before 50 | public void setup() throws Exception { 51 | MockitoAnnotations.initMocks(this); 52 | SUT = new DummyCaller(mDummyCollaboratorMock); 53 | 54 | } 55 | 56 | @Test 57 | /** 58 | * stubbing a method with a generic Answer 59 | * since we need a callback to return immediately (synchronously), 60 | * we generate an answer so when the method under test is called, 61 | * the callback will be executed right away with the data we tell it to return. 62 | */ 63 | public void test_doSomethingAsynchronously_usingDoAnswer() { 64 | //arrange 65 | //here we stub the result 66 | final List results = Arrays.asList("One", "Two", "Three"); 67 | doAnswer(new Answer() { 68 | @Override 69 | public Object answer(InvocationOnMock invocation) throws Throwable { 70 | 71 | ((DummyCallback)invocation.getArguments()[0]).onSuccess(results); 72 | return null; 73 | } 74 | }).when(mDummyCollaboratorMock).doSomethingAsynchronously(any(DummyCallback.class)); 75 | //action 76 | SUT.doSomethingAsynchronously(); 77 | //assert 78 | verify(mDummyCollaboratorMock).doSomethingAsynchronously(any(DummyCallback.class)); 79 | assertThat(SUT.getResult(), is(equalTo(results))); 80 | } 81 | 82 | @Test 83 | public void test_doSomethingAsynchronously_usingArgumentCaptor() { 84 | 85 | //arrange 86 | ArgumentCaptor ac = ArgumentCaptor.forClass(DummyCallback.class); 87 | List results = Arrays.asList("One", "Two", "Three"); 88 | //action 89 | SUT.doSomethingAsynchronously(); 90 | 91 | //assert 92 | verify(mDummyCollaboratorMock).doSomethingAsynchronously(ac.capture()); 93 | // Some assertion about the state before the callback is called 94 | assertThat(SUT.getResult().isEmpty(), is(true)); 95 | 96 | //trigger the reply on callbackCaptor.getValue(). 97 | ac.getValue().onSuccess(results); 98 | 99 | //Some assertion about the state after the callback is called 100 | assertThat(SUT.getResult(), is(equalTo(results))); 101 | 102 | } 103 | 104 | //region helper methods 105 | 106 | //endregion helper methods 107 | 108 | //region helper classes 109 | 110 | //endregion helper classes 111 | 112 | } -------------------------------------------------------------------------------- /app/src/test/java/com/anjan/mockitounittesttutorial/mock/LateInvoiceNotifierTest.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial.mock; 2 | 3 | import org.junit.After; 4 | import org.junit.AfterClass; 5 | import org.junit.Before; 6 | import org.junit.BeforeClass; 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import org.mockito.ArgumentCaptor; 11 | import org.mockito.Mock; 12 | import org.mockito.junit.MockitoJUnitRunner; 13 | 14 | import static org.mockito.Mock.*; 15 | import static org.mockito.Mockito.*; 16 | import static org.hamcrest.CoreMatchers.*; 17 | import static org.junit.Assert.*; 18 | import static org.mockito.ArgumentCaptor.*; 19 | import static org.mockito.ArgumentMatchers.*; 20 | 21 | 22 | /** 23 | * Created by Anjan Debnath on 7/25/2018. 24 | * Copyright (c) 2018, W3 Engineers Ltd. All rights reserved. 25 | */ 26 | @RunWith(MockitoJUnitRunner.class) 27 | public class LateInvoiceNotifierTest { 28 | 29 | //region constants 30 | 31 | //endregion constants 32 | 33 | //region helper fields 34 | private Customer sampleCustomer; 35 | @Mock 36 | EmailSender mEmailSenderMock; 37 | @Mock 38 | InvoiceStorage mInvoiceStorageMock; 39 | @Mock 40 | EventRecorder mEventRecorderMock; 41 | //endregion helper fields 42 | 43 | //Class to be tested 44 | LateInvoiceNotifier SUT; 45 | 46 | @Before 47 | public void setup() throws Exception { 48 | 49 | SUT = new LateInvoiceNotifier(mEmailSenderMock, mInvoiceStorageMock, mEventRecorderMock); 50 | 51 | //set once and used by all methods 52 | sampleCustomer = new Customer(); 53 | sampleCustomer.setFirstName("Harie"); 54 | sampleCustomer.setLastName("Kane"); 55 | 56 | 57 | } 58 | 59 | @Test 60 | public void notifier_foundLateInvoice_emailSendSuccess() throws Exception{ 61 | 62 | //arrange 63 | //by stubbing we can return the value that will be true or false 64 | when(mInvoiceStorageMock.hasOutstandingInvoice(sampleCustomer)).thenReturn(true); 65 | 66 | //action 67 | SUT.notifyLate(sampleCustomer); 68 | 69 | //assert 70 | verify(mEmailSenderMock).sendEmail(sampleCustomer); 71 | 72 | } 73 | 74 | @Test 75 | public void notifier_noLateInvoice_emailSendFailed() { 76 | 77 | //arrange 78 | when(mInvoiceStorageMock.hasOutstandingInvoice(sampleCustomer)).thenReturn(false); 79 | 80 | //action 81 | SUT.notifyLate(sampleCustomer); 82 | 83 | /** 84 | * we want to make sure that the email method is NOT called. 85 | * Therefore, we also add the times argument to restrict 86 | * the number of times this method was (not) called. 87 | * If times is omitted it is assumed to be 1, which is what we do in the first test. 88 | */ 89 | //assert 90 | verify(mEmailSenderMock, times(0)).sendEmail(sampleCustomer); 91 | 92 | } 93 | 94 | @Test 95 | public void notifier_foundLateInvoice_eventWithAC() { 96 | 97 | //arrange 98 | ArgumentCaptor myCaptor = ArgumentCaptor.forClass(Event.class); 99 | when(mInvoiceStorageMock.hasOutstandingInvoice(sampleCustomer)).thenReturn(true); 100 | 101 | //action 102 | SUT.notifyLate(sampleCustomer); 103 | 104 | //assert 105 | verify(mEmailSenderMock).sendEmail(sampleCustomer); 106 | 107 | verify(mEventRecorderMock).recordEvent(myCaptor.capture()); 108 | 109 | Event eventThatWasSent = myCaptor.getValue(); 110 | assertNotNull(eventThatWasSent.getTimestamp()); 111 | assertEquals(Event.Type.REMINDER_SENT, eventThatWasSent.getType()); 112 | assertEquals("Susan Ivanova",eventThatWasSent.getCustomerName()); 113 | } 114 | 115 | //region helper methods 116 | 117 | 118 | //endregion helper methods 119 | 120 | //region helper classes 121 | 122 | //endregion helper classes 123 | 124 | } -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/test/java/com/anjan/mockitounittesttutorial/sync/LoginUseCaseSyncTest.java: -------------------------------------------------------------------------------- 1 | package com.anjan.mockitounittesttutorial.sync; 2 | 3 | 4 | 5 | import com.anjan.mockitounittesttutorial.sync.authtoken.AuthTokenCache; 6 | import com.anjan.mockitounittesttutorial.sync.eventbus.EventBusPoster; 7 | import com.anjan.mockitounittesttutorial.sync.eventbus.LoggedInEvent; 8 | import com.anjan.mockitounittesttutorial.sync.networking.LoginHttpEndpointSync; 9 | import com.anjan.mockitounittesttutorial.sync.networking.NetworkErrorException; 10 | 11 | import org.junit.Before; 12 | import org.junit.Test; 13 | import org.mockito.ArgumentCaptor; 14 | 15 | import java.util.List; 16 | 17 | import static org.hamcrest.CoreMatchers.instanceOf; 18 | import static org.hamcrest.CoreMatchers.is; 19 | import static org.junit.Assert.assertThat; 20 | import static org.mockito.ArgumentMatchers.any; 21 | import static org.mockito.Mockito.doThrow; 22 | import static org.mockito.Mockito.mock; 23 | import static org.mockito.Mockito.times; 24 | import static org.mockito.Mockito.verify; 25 | import static org.mockito.Mockito.verifyNoMoreInteractions; 26 | import static org.mockito.Mockito.when; 27 | 28 | public class LoginUseCaseSyncTest { 29 | 30 | public static final String USERNAME = "username"; 31 | public static final String PASSWORD = "password"; 32 | public static final String AUTH_TOKEN = "authToken"; 33 | 34 | LoginHttpEndpointSync mLoginHttpEndpointSyncMock; 35 | AuthTokenCache mAuthTokenCacheMock; 36 | EventBusPoster mEventBusPosterMock; 37 | 38 | LoginUseCaseSync SUT; 39 | 40 | @Before 41 | public void setup() throws Exception { 42 | mLoginHttpEndpointSyncMock = mock(LoginHttpEndpointSync.class); 43 | mAuthTokenCacheMock = mock(AuthTokenCache.class); 44 | mEventBusPosterMock = mock(EventBusPoster.class); 45 | SUT = new LoginUseCaseSync(mLoginHttpEndpointSyncMock, mAuthTokenCacheMock, mEventBusPosterMock); 46 | successEndPintResult(); 47 | } 48 | 49 | @Test 50 | public void loginSync_success_usernameAndPasswordPassedToEndpoint() throws Exception { 51 | ArgumentCaptor ac = ArgumentCaptor.forClass(String.class); 52 | SUT.loginSync(USERNAME, PASSWORD); 53 | verify(mLoginHttpEndpointSyncMock, times(1)).loginSync(ac.capture(), ac.capture()); 54 | List captures = ac.getAllValues(); 55 | assertThat(captures.get(0), is(USERNAME)); 56 | assertThat(captures.get(1), is(PASSWORD)); 57 | } 58 | 59 | @Test 60 | public void loginSync_success_authTokenCached() throws Exception { 61 | ArgumentCaptor ac = ArgumentCaptor.forClass(String.class); 62 | SUT.loginSync(USERNAME, PASSWORD); 63 | verify(mAuthTokenCacheMock).cacheAuthToken(ac.capture()); 64 | assertThat(ac.getValue(), is(AUTH_TOKEN)); 65 | } 66 | 67 | @Test 68 | public void loginSync_generalError_authTokenNotCached() throws Exception { 69 | generalError(); 70 | SUT.loginSync(USERNAME, PASSWORD); 71 | verifyNoMoreInteractions(mAuthTokenCacheMock); 72 | } 73 | 74 | @Test 75 | public void loginSync_authError_authTokenNotCached() throws Exception { 76 | authError(); 77 | SUT.loginSync(USERNAME, PASSWORD); 78 | verifyNoMoreInteractions(mAuthTokenCacheMock); 79 | } 80 | 81 | @Test 82 | public void loginSync_serverError_authTokenNotCached() throws Exception { 83 | serverError(); 84 | SUT.loginSync(USERNAME, PASSWORD); 85 | verifyNoMoreInteractions(mAuthTokenCacheMock); 86 | } 87 | 88 | @Test 89 | public void loginSync_success_loggedInEventPosted() throws Exception { 90 | ArgumentCaptor ac = ArgumentCaptor.forClass(Object.class); 91 | SUT.loginSync(USERNAME, PASSWORD); 92 | verify(mEventBusPosterMock).postEvent(ac.capture()); 93 | assertThat(ac.getValue(), is(instanceOf(LoggedInEvent.class))); 94 | } 95 | 96 | @Test 97 | public void loginSync_generalError_noInteractionWithEventBusPoster() throws Exception { 98 | generalError(); 99 | SUT.loginSync(USERNAME, PASSWORD); 100 | verifyNoMoreInteractions(mEventBusPosterMock); 101 | } 102 | 103 | @Test 104 | public void loginSync_authError_noInteractionWithEventBusPoster() throws Exception { 105 | authError(); 106 | SUT.loginSync(USERNAME, PASSWORD); 107 | verifyNoMoreInteractions(mEventBusPosterMock); 108 | } 109 | 110 | @Test 111 | public void loginSync_serverError_noInteractionWithEventBusPoster() throws Exception { 112 | serverError(); 113 | SUT.loginSync(USERNAME, PASSWORD); 114 | verifyNoMoreInteractions(mEventBusPosterMock); 115 | } 116 | 117 | @Test 118 | public void loginSync_success_successReturned() throws Exception { 119 | LoginUseCaseSync.UseCaseResult result = SUT.loginSync(USERNAME, PASSWORD); 120 | assertThat(result, is(LoginUseCaseSync.UseCaseResult.SUCCESS)); 121 | } 122 | 123 | @Test 124 | public void loginSync_serverError_failureReturned() throws Exception { 125 | serverError(); 126 | LoginUseCaseSync.UseCaseResult result = SUT.loginSync(USERNAME, PASSWORD); 127 | assertThat(result, is(LoginUseCaseSync.UseCaseResult.FAILURE)); 128 | } 129 | 130 | @Test 131 | public void loginSync_authError_failureReturned() throws Exception { 132 | authError(); 133 | LoginUseCaseSync.UseCaseResult result = SUT.loginSync(USERNAME, PASSWORD); 134 | assertThat(result, is(LoginUseCaseSync.UseCaseResult.FAILURE)); 135 | } 136 | 137 | @Test 138 | public void loginSync_generalError_failureReturned() throws Exception { 139 | generalError(); 140 | LoginUseCaseSync.UseCaseResult result = SUT.loginSync(USERNAME, PASSWORD); 141 | assertThat(result, is(LoginUseCaseSync.UseCaseResult.FAILURE)); 142 | } 143 | 144 | @Test 145 | public void loginSync_networkError_networkErrorReturned() throws Exception { 146 | networkError(); 147 | LoginUseCaseSync.UseCaseResult result = SUT.loginSync(USERNAME, PASSWORD); 148 | assertThat(result, is(LoginUseCaseSync.UseCaseResult.NETWORK_ERROR)); 149 | } 150 | 151 | private void networkError() throws Exception { 152 | doThrow(new NetworkErrorException()) 153 | .when(mLoginHttpEndpointSyncMock).loginSync(any(String.class), any(String.class)); 154 | } 155 | 156 | 157 | //STUB 158 | private void successEndPintResult() throws NetworkErrorException { 159 | when(mLoginHttpEndpointSyncMock.loginSync(any(String.class), any(String.class))) 160 | .thenReturn(new LoginHttpEndpointSync.EndpointResult(LoginHttpEndpointSync.EndpointResultStatus.SUCCESS, AUTH_TOKEN)); 161 | } 162 | 163 | private void generalError() throws Exception { 164 | when(mLoginHttpEndpointSyncMock.loginSync(any(String.class), any(String.class))) 165 | .thenReturn(new LoginHttpEndpointSync.EndpointResult(LoginHttpEndpointSync.EndpointResultStatus.GENERAL_ERROR, "")); 166 | } 167 | 168 | private void authError() throws Exception { 169 | when(mLoginHttpEndpointSyncMock.loginSync(any(String.class), any(String.class))) 170 | .thenReturn(new LoginHttpEndpointSync.EndpointResult(LoginHttpEndpointSync.EndpointResultStatus.AUTH_ERROR, "")); 171 | } 172 | 173 | private void serverError() throws Exception { 174 | when(mLoginHttpEndpointSyncMock.loginSync(any(String.class), any(String.class))) 175 | .thenReturn(new LoginHttpEndpointSync.EndpointResult(LoginHttpEndpointSync.EndpointResultStatus.SERVER_ERROR, "")); 176 | } 177 | 178 | } -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | 4 | # Table of contents 5 | 1. [Introduction](#introduction) 6 | 2. [Community Code of Conduct](#codeofconduct) 7 | 1. [Be considerate](#beconsiderate) 8 | 2. [Be respectful](#berespectful) 9 | 3. [Be collaborative](#becollaborative) 10 | 4. [When you disagree, consult others](#disagree) 11 | 5. [When you're unsure, ask for help](#unsure) 12 | 6. [Step down considerately](#stepdown) 13 | 14 | 3. [Your First Contribution](#firstcontribution) 15 | 4. [Support questions](#supportquestions) 16 | 5. [Reporting issues](#reportissue) 17 | 6. [Fix Bugs](#fixbugs) 18 | 7. [Implement Features](#features) 19 | 8. [Submitting an Issue](#submitissue) 20 | 9. [Feature requests](#featurereq) 21 | 10. [Code review process](#codereview) 22 | 11. [Community](#community) 23 | 12. [Pull Requests](#pullreq) 24 | 1. [How to create PR](#howpullreq) 25 | 13. [Git Commit Guidelines](#gitcommit) 26 | 14. [Coding style guide](#codingstyle) 27 | 15. [Organize github issues](#organize) 28 | 16. [Issue Referencing on Github](#issuereference) 29 | 30 | 31 | 32 | ## Introduction 33 | 34 | First off, thank you for considering contributing to MockTest. It's people like you that make MockTest such a great tool. 35 | 36 | When contributing to this repository, please first discuss the change you wish to make via issue ticket ([sample](https://github.com/anjandebnath/MockitoUnitTestTutorial/issues/5)) with the owners of this repository before making a change. 37 | 38 | Please note we have a code of conduct, please follow it in all your interactions with the project. 39 | 40 | When contributing to MockTest, we ask that you: 41 | 42 | - let us know what you plan in the [GitHub Issue tracker](https://github.com/anjandebnath/MockitoUnitTestTutorial/projects/2) so we can provide feedback. 43 | 44 | - provide tests and documentation whenever possible. It is very unlikely that we will accept new features or functionality into MockTest without the proper testing and documentation. When fixing a bug, provide a failing test case that your patch solves. 45 | 46 | - open a GitHub Pull Request with your patches and we will review your contribution and respond as quickly as possible. Keep in mind that this is an open source project, and it may take us some time to get back to you. Your patience is very much appreciated. 47 | 48 | 49 | 50 | ## Community Code of Conduct 51 | 52 | 53 | The goal is to maintain a MockTest community that's pleasant for everyone. 54 | That's why we would greatly appreciate it if everyone contributing to and 55 | interacting with the community also followed this Code of Conduct. 56 | 57 | 58 | ### Be considerate 59 | 60 | 61 | Your work will be used by other people, and you in turn will depend on the 62 | work of others. Any decision you take will affect users and colleagues, and 63 | we expect you to take those consequences into account when making decisions. 64 | Even if it's not obvious at the time, our contributions to MockTest will impact 65 | the work of others. For example, changes to code, infrastructure, policy, 66 | documentation and translations during a release may negatively impact 67 | others work. 68 | 69 | ### Be respectful 70 | 71 | 72 | The MockTest community and its members treat one another with respect. Everyone 73 | can make a valuable contribution to MockTest. We may not always agree, but 74 | disagreement is no excuse for poor behavior and poor manners. We might all 75 | experience some frustration now and then, but we cannot allow that frustration 76 | to turn into a personal attack. It's important to remember that a community 77 | where people feel uncomfortable or threatened isn't a productive one. We 78 | expect members of the MockTest community to be respectful when dealing with 79 | other contributors as well as with people outside the MockTest project and with 80 | users of MockTest. 81 | 82 | ### Be collaborative 83 | 84 | 85 | Collaboration is central to MockTest and to the larger free software community. 86 | We should always be open to collaboration. Your work should be done 87 | transparently and patches from MockTest should be given back to the community 88 | when they're made, not just when the distribution releases. If you wish 89 | to work on new code for existing upstream projects, at least keep those 90 | projects informed of your ideas and progress. It many not be possible to 91 | get consensus from upstream, or even from your colleagues about the correct 92 | implementation for an idea, so don't feel obliged to have that agreement 93 | before you begin, but at least keep the outside world informed of your work, 94 | and publish your work in a way that allows outsiders to test, discuss, and 95 | contribute to your efforts. 96 | 97 | ### When you disagree, consult others 98 | 99 | 100 | Disagreements, both political and technical, happen all the time and 101 | the MockTest community is no exception. It's important that we resolve 102 | disagreements and differing views constructively and with the help of the 103 | community and community process. If you really want to go a different 104 | way, then we encourage you to make a derivative distribution or alternate 105 | set of packages that still build on the work we've done to utilize as common 106 | of a core as possible. 107 | 108 | ### When you're unsure, ask for help 109 | 110 | 111 | Nobody knows everything, and nobody is expected to be perfect. Asking 112 | questions avoids many problems down the road, and so questions are 113 | encouraged. Those who are asked questions should be responsive and helpful. 114 | However, when asking a question, care must be taken to do so in an appropriate 115 | forum. 116 | 117 | ### Step down considerately 118 | 119 | Developers on every project come and go and MockTest is no different. When you 120 | leave or disengage from the project, in whole or in part, we ask that you do 121 | so in a way that minimizes disruption to the project. This means you should 122 | tell people you're leaving and take the proper steps to ensure that others 123 | can pick up where you leave off. 124 | 125 | 126 | ## Your First Contribution 127 | 128 | Unsure where to begin contributing to MockTest? You can start by looking through these `good-first` and `help-wanted` issues: 129 | 130 | * [Good first issues](https://github.com/anjandebnath/MockitoUnitTestTutorial/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) - issues which should only require a few lines of code, and a test or two. 131 | * [Help wanted issues](https://github.com/anjandebnath/MockitoUnitTestTutorial/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) - issues which should be a bit more involved than `good-first` issues. 132 | 133 | Both issue lists are sorted by total number of comments. While not perfect, number of comments is a reasonable proxy for impact a given change will have. 134 | 135 | Working on your first Pull Request? You can learn how from this *free* series, [How to Contribute to an Open Source Project on GitHub](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github). 136 | 137 | At this point, you're ready to make your changes! Feel free to ask for help; everyone is a beginner at first :smile_cat: 138 | 139 | If a maintainer asks you to "rebase" your PR, they're saying that a lot of code has changed, and that you need to update your branch so it's easier to merge. 140 | 141 | 142 | ## Support questions 143 | 144 | 145 | Please, don't use the issue tracker for this. Use one of the following 146 | resources for questions about your own code: 147 | 148 | * The ``#get-help`` channel on our [Discord chat](comming soon) 149 | 150 | * The mailing list media@MockTest.net for long term discussion or larger issues. 151 | 152 | 153 | ## Reporting issues 154 | 155 | Report bugs at https://github.com/anjandebnath/MockitoUnitTestTutorial/issues. 156 | 157 | We have different templates for bug report and feature request which you can find during issue creation. 158 | 159 | ```text 160 | 161 | 162 | 163 | ### Description 164 | 165 | 166 | ### Expected Behavior 167 | 168 | 169 | ### Actual Behavior 170 | 171 | 172 | ### Possible Fix 173 | 174 | 175 | ### Steps to Reproduce 176 | 177 | 178 | 1. 179 | 2. 180 | 3. 181 | 4. 182 | 183 | ### Context 184 | 185 | 186 | ### Your Environment 187 | 188 | * App version used: 189 | * Device Name and version: 190 | * Operating System and version: 191 | 192 | ``` 193 | 194 | 195 | ## Fix Bugs 196 | 197 | Look through the GitHub issues for bugs. Anything tagged with "bug" 198 | is open to whoever wants to implement it. 199 | [Sample issue](https://github.com/anjandebnath/MockitoUnitTestTutorial/issues/5) 200 | 201 | 202 | ## Implement Features 203 | 204 | 205 | Look through the GitHub issues for features. Anything tagged with "enhancement" 206 | and "optimization" is open to whoever wants to implement it. 207 | 208 | Please do not combine multiple feature enhancements into a single pull request. 209 | 210 | Note: We're trying to keep the code base 211 | small, extensible, and streamlined. Whenever possible, it's best to try and 212 | implement feature ideas as separate projects outside of the core codebase. 213 | 214 | 215 | 216 | ## Submitting an Issue 217 | 218 | Before you submit an issue, 219 | **search** the issues archive; 220 | maybe the issue has already been submitted or considered. If the issue appears to be a bug, 221 | and hasn't been reported, open a [new issue](https://github.com/anjandebnath/MockitoUnitTestTutorial/issues/new/choose). 222 | 223 | > Please **do not report duplicate issues**; help us maximize the effort we can spend fixing 224 | issues and adding enhancements. 225 | 226 | Providing the following information will increase the chances of your issue being dealt with 227 | quickly: 228 | 229 | * **Issue Title** - provide a concise issue title prefixed with a snake-case name of the 230 | associated service or component (if any): `: `. 231 | Adding the `md-` prefix should be avoided. 232 | 233 | > e.g. 234 | > * unit-test: mockito library syncing problem [#5](https://github.com/anjandebnath/MockitoUnitTestTutorial/issues/5) 235 | 236 | 237 | * **Complete the full Issue Template** - You will get the issue template where we put some predefined rules to create an issue. 238 | Moreover we are always open to make any changes according contributor's feedback. 239 | 240 | * **Suggest a Fix** - if you can't fix the bug yourself, perhaps you can point to what might be 241 | causing the problem (line of code or commit). 242 | 243 | #### Submitting Pull Requests 244 | 245 | **Important**: We are not accepting major feature requests or PRs that contain major new features 246 | or breaking changes at this time but we are welcoming to plan it for future or, we can discuss further offline. 247 | 248 | 249 | ## Feature requests 250 | 251 | If you find yourself wishing for a feature that doesn't exist in MockTest, you are probably not alone. There are bound to be others out there with similar needs. Many of the features that MockTest has today have been added because our users saw the need. Open an issue on our issues list on GitHub which describes the feature you would like to see, why you need it, and how it should work. 252 | 253 | ## Code review process 254 | 255 | The core team looks at Pull Requests on a regular basis.Each code review should aim to achieve one or more of these goals; however, not all code reviews need to aim for all goals. 256 | 257 | Code review goals: 258 | 259 | - Finding bugs 260 | - Bugs found in code review require much less effort to find & fix than bugs found in QA/testing. 261 | - Coding style. Ensure that [Android coding standard](https://github.com/ustwo/android-coding-standards) and [Coding Pattern](https://blog.mindorks.com/android-code-style-and-guidelines-d5f80453d5c7) are followed. 262 | - Improving code quality 263 | - Teaching best practices 264 | - Code consistency (can't tell the author from the code) 265 | - Learning code 266 | - Efficiency (getting pull requests reviewed quickly) 267 | - Ensuring that the pull request guidelines are followed. 268 | 269 | 270 | Code review processes: 271 | 272 | - Issue a pull request with a full link to your ticket in the description. 273 | - Click the "Request Review" option on the ticket to move into the "Code Review (pre commit)" state. 274 | - Add a comment linking to your pull request by its url. 275 | 276 | Code review checklists : 277 | 278 | - Variable naming convention. 279 | - Method naming convention. 280 | - is the Class file is written in suitable package that is defined in guideline. 281 | - Override methods should be listed upper and then the private methods. 282 | - xml naming convention. 283 | - Layout design. 284 | - Unit test check. 285 | - Proper commenting on each method. 286 | - Method body and if any logical improvement is needed. 287 | - If any 3rd party library used then is it good to use or not 288 | - No sophisticated url access/data on git commit 289 | 290 | ## Community 291 | 292 | We will finalise our contributors community and list down their details soon 293 | 294 | ## Pull Requests 295 | 296 | Follow all instructions in [the template](https://github.com/anjandebnath/MockitoUnitTestTutorial/blob/master/PULL_REQUEST_TEMPLATE.md) 297 | The process described here has several goals: 298 | 299 | - Maintain MockTest's code quality 300 | - Fix problems that are important to users 301 | - Engage the community in working toward the best possible MockTest 302 | - Enable a sustainable system for MockTest's maintainers to review contributions 303 | 304 | ### How to create PR 305 | 306 | [How to create PR on Github](https://www.digitalocean.com/community/tutorials/how-to-create-a-pull-request-on-github) 307 | 308 | [How to update existing PR](https://www.digitalocean.com/community/tutorials/how-to-rebase-and-update-a-pull-request) 309 | 310 | 311 | ## Git Commit Guidelines 312 | 313 | We have very precise rules over how our git commit messages can be formatted. This leads to **more 314 | readable messages** that are easy to follow when looking through the **project history**. 315 | 316 | 317 | ### Commit Message Format 318 | Each commit message consists of a **header**, a **body** and a **footer**. The header has a special 319 | format that includes a **type**, a **scope** and a **subject**: 320 | 321 | ```html 322 | (): 323 | 324 | 325 | 326 |