My class to be tested is of HostApi with the static logger.
public class HostApi {
String baseUrl;
private static Logger logger=LogFactory.getLogger(HostApi.class);
/**
* Constructor
*
* #param baseUrl
* - protocol + "://" + dockerIp + ":" + dockerPort Example -
* http://192.168.99.100:2375
*/
public HostApi(String baseUrl) {
this.baseUrl = baseUrl;
}
HostRestClient client;
public Container getContainerInfo(String containerId) throws IOException, AgentException {
logger.debug("############# getContainerInfo start ###################"); //$NON-NLS-1$
String output;
String path = "/containers/" + containerId + "/json"; //$NON-NLS-1$ //$NON-NLS-2$
client = new HostRestClient();
output = client.processGetRequest(baseUrl + path);
logger.trace(output);
ObjectMapper mapper = new ObjectMapper();
Container container = mapper.readValue(output, Container.class);
logger.debug("############# getContainerInfo end ###################\n\n"); //$NON-NLS-1$
return container;
}
}
My JUnit test class is HostApiTest
#RunWith(PowerMockRunner.class)
#PrepareForTest({HostApi.class,ObjectMapper.class,LogFactory.class})
public class HostApiTest {
HostApi hp;
static Logger logger;
#BeforeClass
public static void before()
{
System.out.println("Before Class");
}
#AfterClass
public static void after() {
System.out.println("After Class");
}
#Mock
Logger loggermock;
#Before()
public void setUp() {
mockStatic(LogFactory.class);
EasyMock.expect(LogFactory.getLogger(HostApi.class)).andReturn(loggermock );
//logger=createMock(Logger.class);
// Whitebox.setInternalState(HostApi.class, logger);
hp=new HostApi("skj"); //$NON-NLS-1$
}
#Test
public void testgetContainerInfo() throws Exception{
System.out.println("abc");
HostRestClient client=PowerMock.createMock(HostRestClient.class);
ObjectMapper obj=PowerMock.createMock(ObjectMapper.class);
Container container=new Container();
container.setId("234");
String containerData=container.toString();
PowerMock.expectNew(ObjectMapper.class).andReturn(obj);
PowerMock.expectNew(HostRestClient.class).andReturn(client);
EasyMock.expect(client.processGetRequest(EasyMock.isA(String.class))).andReturn(containerData);
EasyMock.expect(obj.readValue(EasyMock.isA(String.class),EasyMock.same(Container.class))).andReturn(container);
replayAll();
assertEquals("234",hp.getContainerInfo("25").getId());
EasyMock.verify();
}
}
Without the logger in the code (i.e. commenting out in HostApi) it works, however after adding logger it throws assertion error
I added static mocking of logfactory however it does not seem to work.
What is it that I am doing wrong in mocking? I can only use powermock.
Remove ...
LogFactory.class from the #PrepareForTest({...}) annotation
#Mock Logger loggermock; from HostApiTest
mockStatic(LogFactory.class); from HostApiTest
EasyMock.expect(LogFactory.getLogger(HostApi.class)).andReturn(loggermock); from HostApiTest
Your test case has no expectations or assertions on the behaviour of the HostApi's logger so there is no need to mock it.
Related
I am getting an exception when I am running this code, I am closing the testContext in beforeEach and test Method.
The test execution timed out. Make sure your asynchronous code includes calls to either VertxTestContext#completeNow(), VertxTestContext#failNow() or Checkpoint#flag()
java.util.concurrent.TimeoutException: The test execution timed out. Make sure your asynchronous code includes calls to either VertxTestContext#completeNow(), VertxTestContext#failNow() or Checkpoint#flag()
at io.vertx.junit5.VertxExtension.joinActiveTestContexts(VertxExtension.java:230)
#DisplayName("Test Case Workflow")
#ExtendWith(VertxExtension.class)
public class OrchestrationDBVerticleTest {
// tag::prepare[]
private Vertx vertx;
private OrchestrationDBService service;
public static final String CONFIG_JDBC_URL = "test.jdbc.url";
public static final String CONFIG_JDBC_DRIVER_CLASS = "test.jdbc.driver_class";
public static final String CONFIG_JDBC_MAX_POOL_SIZE = "test.jdbc.max_pool_size";
#BeforeEach
public void prepare(VertxTestContext testContext) throws InterruptedException {
vertx = Vertx.vertx();
JsonObject config = new JsonObject()
.put("url", vertx.getOrCreateContext().config().getString(CONFIG_JDBC_URL, "jdbc:hsqldb:mem:testdb"))
.put("driver_class", vertx.getOrCreateContext().config().getString(CONFIG_JDBC_DRIVER_CLASS, "org.hsqldb.jdbcDriver"))
.put("max_pool_size", vertx.getOrCreateContext().config().getInteger(CONFIG_JDBC_MAX_POOL_SIZE, 30));
JsonObject dbConfig = new JsonObject().put("jdbcConfig", config);
vertx.deployVerticle(new OrchestrationDBVerticle(), new DeploymentOptions().setConfig(dbConfig),
testContext.succeeding(id -> {
service = OrchestrationDBService.createProxy(vertx, OrchestrationDBVerticle.CONFIG_ORCHESTRATION_DB_QUEUE);
testContext.completeNow();
}));
}
// end::prepare[]
// tag::finish[]
#AfterEach
public void finish(VertxTestContext testContext) {
System.out.println("after");
vertx.close();
}
// end::finish[]
// tag::crud[]
#Test
public void crud_operations(VertxTestContext testContext) {
// Checkpoint callProxy = testContext.checkpoint();
JsonObject jobInput = (new JsonObject()).put("requestInput", new JsonObject().put("test", "test"))
.put("workflow", "WorkFlowHandler");
service.saveJobDetails(jobInput, testContext.succeeding(response -> {
System.out.println("Service Response : " + response);
Assertions.assertThat(response.toString().contains("IN_QUEUE"));
testContext.completeNow();
// callProxy.flag();
}));
}
// end::crud[]
}
EDIT: -
I was not completing testContext in the finish method.
#AfterEach
public void finish(VertxTestContext testContext) {
System.out.println("after");
vertx.close(testContext.succeeding(response -> {
testContext.completeNow();
}));
}
But Even after that my asserstion condtions are always true if I provide wrong input.
Solved.
I was not completing testContext in the finish method.
#AfterEach
public void finish(VertxTestContext testContext) {
System.out.println("after");
vertx.close(testContext.succeeding(response -> {
testContext.completeNow();
}));
}
Update:- Verifying the assertions in testContext.verify()
#Test
#DisplayName("🚀 Return Exact request what we stored in DB")
public void crud_operations(VertxTestContext testContext) {
JsonObject jobInput = (new JsonObject()).put("requestInput", new JsonObject().put("test", "test"))
.put("workflow", "CaseWorkFlowHandler");
service.saveJobDetails(jobInput, testContext.succeeding(response -> {
testContext.verify(() -> {
Assertions.assertThat(response.getJsonArray("rows").getJsonObject(0).getString("REQUEST_INPUT")).isEqualTo("{\"test\":\"test\"}");
});
testContext.completeNow();
}));
}
I'm trying to refactor one pretty old project, so I started implementing new architecture (MVVM) with Dagger2, RxJava, RxAndroid... Now everything is connected and working fine, now the problem is, I have no idea how to write a Unit test for my ViewModel..
I want to start with Login screen first, so I created a LoginViewModel, but first let me show you what I did..
I have a DataModule that provides 2 classes, RestApiRepository and ViewModelFactory. RestApiRepository looks like this:
public class RestApiRepository {
private RestClient restClient;
public RestApiRepository(RestClient restClient) {
this.restClient = restClient;
}
public Observable<AuthResponseEntity> authenticate(String header, AuthRequestEntity requestEntity) {
return restClient.postAuthObservable(header, requestEntity);
}
}
Rest client with api call for login:
public interface RestClient {
#POST(AUTH_URL)
Observable<AuthResponseEntity> postAuthObservable(#Header("Authorization") String authKey, #Body AuthRequestEntity requestEntity);
}
Second class from DataModule is ViewModelFactory:
#Singleton
public class ViewModelFactory extends ViewModelProvider.NewInstanceFactory implements ViewModelProvider.Factory {
private RestApiRepository repository;
#Inject
public ViewModelFactory(RestApiRepository repository) {
this.repository = repository;
}
#NonNull
#Override
public <T extends ViewModel> T create(#NonNull Class<T> modelClass) {
if (modelClass.isAssignableFrom(LoginViewModel.class)) {
return (T) new LoginViewModel(repository);
}
throw new IllegalArgumentException("Unknown class name");
}
}
And finally, LoginViewModel:
public class LoginViewModel extends ViewModel {
private final CompositeDisposable disposable = new CompositeDisposable();
private final MutableLiveData<AuthResponseEntity> responseLiveData = new MutableLiveData<>();
private RestApiRepository restApiRepository;
private SchedulerProvider provider;
public LoginViewModel(RestApiRepository restApiRepository, SchedulerProvider provider) {
this.restApiRepository = restApiRepository;
this.provider = provider;
}
public MutableLiveData<AuthResponseEntity> getResponseLiveData() {
return responseLiveData;
}
#Override
protected void onCleared() {
disposable.clear();
}
public void auth(String token, AuthRequestEntity requestEntity) {
if (token != null && requestEntity != null) {
disposable.add(restApiRepository.authenticate(token, requestEntity)
.subscribeOn(provider.io())
.observeOn(provider.ui())
.subscribeWith(new DisposableObserver<AuthResponseEntity>() {
#Override
public void onNext(AuthResponseEntity authResponseEntity) {
responseLiveData.setValue(authResponseEntity);
}
#Override
public void onError(Throwable e) {
AuthResponseEntity authResponseEntity = new AuthResponseEntity();
authResponseEntity.setErrorMessage(e.getMessage());
responseLiveData.setValue(authResponseEntity);
}
#Override
public void onComplete() {
}
}
));
}
}
}
So, I'm sure everything is connected well, I can successfuly login...
For the RxAndroid test issues, I found somewhere that I have to use this Scheduler provider like this:
public class AppSchedulerProvider implements SchedulerProvider {
public AppSchedulerProvider() {
}
#Override
public Scheduler computation() {
return Schedulers.trampoline();
}
#Override
public Scheduler io() {
return Schedulers.trampoline();
}
#Override
public Scheduler ui() {
return Schedulers.trampoline();
}
}
Below is my LoginViewModelTest class, but I don't know how to handle RxJava/RxAndroid inside the tests..
#RunWith(MockitoJUnitRunner.class)
public class LoginViewModelTest {
#Mock
private RestApiRepository restApiRepository;
#Mock
private MutableLiveData<AuthResponseEntity> mutableLiveData;
private LoginViewModel loginViewModel;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
AppSchedulerProvider schedulerProvider = new AppSchedulerProvider();
loginViewModel = Mockito.spy(new LoginViewModel(restApiRepository, schedulerProvider));
}
#Test
public void authenticate_error() {
String token = "token";
AuthRequestEntity requestEntity = Mockito.mock(AuthRequestEntity.class);
Mockito.doReturn(Observable.error(new Throwable())).when(restApiRepository).authenticate(token, requestEntity);
loginViewModel.auth(token, requestEntity);
AuthResponseEntity responseEntity = Mockito.mock(AuthResponseEntity.class);
responseEntity.setErrorMessage("Error");
Mockito.verify(mutableLiveData).setValue(responseEntity);
}
}
So, I wanted to write a test for failed case when onError is called, but when I run it, I get this error:
exclude patterns:io.reactivex.exceptions.UndeliverableException: The exception could not be delivered to the consumer because it has already canceled/disposed the flow or the exception has nowhere to go to begin with. Further reading: https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#error-handling | java.lang.RuntimeException: Method getMainLooper in android.os.Looper not mocked. See http://g.co/androidstudio/not-mocked for details.
You can mock the behaviour of restApiRepository:
Mockito.when(restApiRepository.authenticate(token, requestEntity)).thenReturn(Observable.error(error));
and verify that responseLiveData.setValue is being called with the appropriate parameters
I have the following code I'm trying to unit test :
if (networkUtils.isOnline()) {
return remoteDataSource.postComment(postId, commentText)
.doOnSuccess(postCommentResponse ->
localDataSource.postComment(postId, commentText))
.subscribeOn(schedulerProvider.io())
.observeOn(schedulerProvider.mainThread());
} else {
return Single.error(new IOException());
}
And this is how I'm trying to test it :
#Test
public void postComment_whenIsOnline_shouldCallLocalToPostComment() throws Exception {
// Given
when(networkUtils.isOnline())
.thenReturn(true);
String postId = "100";
String comment = "comment";
Response<PostCommentResponse> response = postCommentResponse();
when(remoteDataSource.postComment(anyString(), anyString()))
.thenReturn(Single.just(response));
// When
repository.postComment(postId, comment);
// Then
verify(localDataSource).postComment(postId, comment);
}
where I fake Response from Retrofit like :
private Response<PostCommentResponse> postCommentResponse() {
PostCommentResponse response = new PostCommentResponse();
response.setError("0");
response.setComment(postCommentResponseNestedItem);
return Response.success(response);
}
but it results to : Actually, there were zero interactions with this mock.
Any ideas ?
EDIT :
#RunWith(MockitoJUnitRunner.class)
public class CommentsRepositoryTest {
#Mock
private CommentsLocalDataSource localDataSource;
#Mock
private CommentsRemoteDataSource remoteDataSource;
#Mock
private NetworkUtils networkUtils;
#Mock
private PostCommentResponseNestedItem postCommentResponseNestedItem;
private CommentsRepository repository;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
BaseSchedulerProvider schedulerProvider = new ImmediateSchedulerProvider();
repository = new CommentsRepository(localDataSource, remoteDataSource, networkUtils, schedulerProvider);
}
// tests
}
When you want to test an Observable you have to subscribe to it so it will start emitting items.
As soon as I used :
TestObserver<Response<PostCommentResponse>> testObserver = new TestObserver<>();
and subscribed to :
repository.postComment(postId, comment)
.subscribe(testObserver);
the test worked as expected.
I'm trying to test the start method of an Activity that uses RequestFactory.
I manage to test RF calls invoking directly the service using this article example, but I'm missing something mocking RF calls called from the tested activity.
It's more clear with the code.
EDIT : more specific
What I really want to know, is how to replace the response of a Receiver method (onSuccess,onFailure...) called in an Activity? This way I would be able to test the code inside the receiver method.
So basically here is my activity :
public class MyActivity extends AbstractActivity implements MyView.Presenter {
private List<MyEntityProxy> entities;
private MyView view;
private ClientFactory cf;
private EntityRequest entityRequest;
private AppRequestFactory rf;
#Inject
public ClientsListActivity(ClientsListViewEditor view, ClientFactory clientFactory) {
this.view = view;
this.clientFactory = clientFactory;
rf = clientFactory.getRequestFactory();
}
#Override
public void start(final AcceptsOneWidget panel, EventBus eventBus) {
view.setPresenter(this);
refreshEntities();
}
public void refreshEntities(){
entityRequest = rf.entityRequest();
entityRequest.getAll().with("opt1,"opt2").fire(new Receiver<List<MyEntityProxy>>() {
#Override
public void onSuccess(List<MyEntityProxy> response) {
entities = response;
entityRequest = requestFactory.clientRequest();
}
});
}
public List<MyEntityProxy> getEntities(){
return entities;
}
}
To test it in JUnit I use GwtMockito, so here is the test class MyActivityTest :
#RunWith(GwtMockitoTestRunner.class)
public class ClientListActivityTest{
private MyActivity activity;
private EventBus eventBus;
private AppRequestFactory rf;
#GwtMock
private ClientFactory cf;
#GwtMock
private MyView;
#GwtMock
private AcceptsOneWidget panel;
#Before
public void setUp(){
eventBus = new SimpleEventBus();
rf = RequestFactoryHelper.create(AppRequestFactory.class);
cf = new ClientFactory(eventBus,rf);
activity = new MyActivity(view,cf);
}
#Test
public void testStartActivity(){
List<EntityProxy> result = new ArrayList<EntityProxy>();
EntityProxy expectedClient = mock(EntityProxy.class);
expectedEntity.setNom("Client 1");
EntityProxy expectedClient2 = mock(EntityProxy.class);
expectedEntity.setNom("Client 2");
result.add(expectedEntity);
result.add(expectedEntity2);
//Here I have to change the requestFactory Call, so I try that but without success :
Request<?> req = mock(Request.class);
doReturn(req).when(mock(MyEntityRequest.class)).getAll();
doAnswer(RequestFactoryHelper.ok(result)).when(req).fire(any(Receiver.class));
activity.start(panel, eventBus);
assertEquals(activity.getEntities().size(),2); //This Test fails size = 0
}
}
My RequestFactoryHelper (inspired from here ) :
public class RequestFactoryHelper {
private static class MockServiceLocator implements ServiceLocator {
private final Map<Class<?>, Object> services = new HashMap<Class<?>, Object>();
#Override
public Object getInstance( Class<?> clazz ) {
// Make sure to return always the same mocked instance for each requested type
Object result = services.get( clazz );
if (result == null) {
result = mock( clazz );
services.put( clazz, result );
}
return result;
}
}
private static class MockServiceDecorator extends ServiceLayerDecorator {
#Override
public <T extends ServiceLocator> T createServiceLocator( Class<T> clazz ) {
return (T) serviceLocator;
}
}
private static MockServiceLocator serviceLocator = new MockServiceLocator();
private static ServiceLayer serviceLayer = ServiceLayer.create( new MockServiceDecorator() );
/**
* Creates a {#link RequestFactory}.
*/
public static <T extends RequestFactory> T create( Class<T> requestFactoryClass ) {
SimpleRequestProcessor processor = new SimpleRequestProcessor( serviceLayer );
T factory = RequestFactorySource.create( requestFactoryClass );
factory.initialize( new SimpleEventBus(), new InProcessRequestTransport( processor ) );
return factory;
}
/**
* Returns the same service instance as used by the RequestFactory internals.
*/
public static <T> T getService( Class<T> serviceClass ) {
T result = (T) serviceLocator.getInstance( serviceClass );
reset( result ); // reset mock to avoid side effects when used in multiple tests
return result;
}
/**
* Returns the value passed to {#link Receiver#onSuccess(Object)}
*/
public static <T> T captureResult( Receiver<T> receiver ) {
ArgumentCaptor<Object> captor = ArgumentCaptor.forClass( Object.class );
verify( receiver ).onSuccess( (T) captor.capture() );
return (T) captor.getValue();
}
public static <T> Answer<T> ok(final T result) {
return new Answer<T>() {
#Override
public T answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
Object _receiver = args[args.length - 1];
Receiver<T> receiver = (Receiver<T>)_receiver;
receiver.onSuccess(result);
return null;
}
};
}
}
This is how I tested the Receiver method "onSuccess". I created a custom Answer for Mockito.doAnswer.
The code to test.
public void myMethod(String arg1, String arg2) {
requestFactory.adminRequest().someMethod(arg1, arg2).fire(new Receiver<Void>() {
#Override
public void onSuccess(Void response) {
placeController.goTo(new MyPlace());
}
});
}
The test.
#Test
public void testMyMethod() {
String arg1 = "arg1";
String arg2 = "arg2";
when(requestFactory.adminRequest()).thenReturn(adminRequest);
when(adminRequest.someMethod(arg1, arg2)).thenReturn(request);
doAnswer(new Answer<Void>() {
#Override
public Void answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
Receiver<Void> receiver = (Receiver<Void>) args[0];
receiver.onSuccess(null);
return null;
}
}).when(request).fire(any(Receiver.class));
myActivity.myMethod(arg1, arg2);
verify(adminRequest).someMethod(arg1, arg2);
verify(request).fire(any(Receiver.class));
verify(placeController).goTo(any(myPlace.class));
}
requestFactory, adminRequest, request and placeController are all mocks.
This is my unit testing code.
public class StatsTest extends AbstractTestCase {
#Mock
//EmailInfo mockMetricsEmail = Mockito.mock(EmailInfo.class);
//EmailSenderImpl mockEmailSenderImpl = Mockito.mock(EmailSenderImpl.class);
private MultiPartEmail mockMultiPartEmail = Mockito.mock(HtmlEmail.class);
private static final String testEmailBody = "This is the test email body.";
private static final String testSender = "seemakur#amazon.com";
private static final String testRecipient = ("seemakur#amazon.com");
private static final String testEmailSubject = "subject";
private static final String testHostName = "seemakur.desktop.amazon.com";
private static final MultiPartEmail testHtmlEmail = new HtmlEmail();
EmailSenderImpl emailSenderImplObj = new EmailSenderImpl();
EmailInfo emailInfoObj = new EmailInfo(testEmailBody, testSender, testRecipient, testEmailSubject, testHostName, testHtmlEmail);
#Before
public void setUp() throws Throwable {
super.setUp();
MockitoAnnotations.initMocks(this); // will instantiate "mockMultiPartEmail"
// instantiate our class under test
}
#Test(expected = EmailException.class)
public void testSendEmail() throws EmailException, IOException {
MultiPartEmail testMultiPartEmail = Mockito.spy(new HtmlEmail());
Mockito.doReturn(mockMultiPartEmail).when(emailInfoObj).getMultiPartEmail(); //stub(spy.getMultiPartEmail()).toReturn(mockMultiPartEmail);
Mockito.when(mockMultiPartEmail.send()).thenThrow(new EmailException("Failed on multipartEmail.send(), hence could not send the email."));
// when the method under test is called
try {
//testEmailSenderImplObj.sendHtmlTableAsEmail(testMetricsEmail);
emailSenderImplObj.sendHtmlTableAsEmail(emailInfoObj); //inject mock & invoke what to test
fail("Expecting EmailException");
}catch(EmailException e){
e.printStackTrace();
}
Mockito.verify(mockMultiPartEmail).send();Mockito.doReturn(mockMultiPartEmail).when(emailInfoObj).getMultiPartEmail(); //stub(spy.getMultiPartEmail()).toReturn(mockMultiPartEmail);
}
}
i have three classes associated with this email function:
firstly below is emailInfo data object
#Data
public class EmailInfo {
private String emailBody;
private String senderEmail;
private String receiversEmails;
private String emailSubject;
private String hostName;
private MultiPartEmail multiPartEmail;
public EmailInfo(String emailBody, String senderEmail, String receiversEmails, String emailSubject, String hostName, MultiPartEmail multiPartEmail) {
this.setEmailBody(emailBody);
this.setSenderEmail(senderEmail);
this.setReceiversEmails(receiversEmails);
this.setEmailSubject(emailSubject);
this.setHostName(hostName);
this.setMultiPartEmail(multiPartEmail);
}
public String getSenderEmail() {
return senderEmail;
}
public void setSenderEmail(String senderEmail) {
this.senderEmail = senderEmail;
}
public String getEmailBody() {
return emailBody;
}
public void setEmailBody(String emailBody) {
this.emailBody = emailBody;
}
public String getReceiversEmails() {
return receiversEmails;
}
public void setReceiversEmails(String receiversEmails2) {
this.receiversEmails = receiversEmails2;
}
public String getEmailSubject() {
return emailSubject;
}
public void setEmailSubject(String emailSubject) {
this.emailSubject = emailSubject;
}
public String getHostName() {
return hostName;
}
public void setHostName(String hostName) {
this.hostName = hostName;
}
public MultiPartEmail getMultiPartEmail() {
return multiPartEmail;
}
public void setMultiPartEmail(MultiPartEmail multiPartEmail) {
this.multiPartEmail = multiPartEmail;
}
}
second class: EmailSenderImpl.java
public class EmailSenderImpl implements EmailSender{
// public MultiPartEmail getEmail(){
// return multiPartEmail;
// }
//
// public void setEmail(MultiPartEmail multiPartEmail){
// this.multiPartEmail = multiPartEmail;
// }
public void sendHtmlTableAsEmail(EmailInfo emailInfo)throws IOException, EmailException{
MultiPartEmail multiPartEmail = new HtmlEmail();
multiPartEmail.setHostName(emailInfo.getHostName());
multiPartEmail.addTo(emailInfo.getReceiversEmails());
multiPartEmail.setFrom(emailInfo.getSenderEmail());
multiPartEmail.setSubject(emailInfo.getEmailSubject());
multiPartEmail.setMsg((emailInfo.getEmailBody()).toString());
multiPartEmail.send();
}
}
lastly the EMailSender.java interface.
public interface EmailSender{
public abstract void sendHtmlTableAsEmail(EmailInfo emailInfo)throws IOException, EmailException;
}
I reason I have so many classes for one simple function is because i cannot use static methods, and i have to separate "business logic" from "function logic." And I need to have interfaces, that is necessary. If there is a better way to organize this, please let me know.
Now when I run the unit test, it fails on the line: "Mockito.doReturn(mockMultiPartEmail).when(emailInfoObj).getMultiPartEmail(); //stub(spy.getMultiPartEmail()).toReturn(mockMultiPartEmail);
");"
the error reads: org.mockito.exceptions.misusing.NotAMockException
In your original code, your problem is that on this line
Mockito.doReturn(mockMultiPartEmail).when(emailInfoObj).getMultiPartEmail();
you are trying to stub the behaviour of the created with this line
EmailInfo emailInfoObj = new EmailInfo(testEmailBody, testSender, testRecipient, testEmailSubject, testHostName, testHtmlEmail);
But this is not a mock or a spy. Mockito only lets you stub the behaviour of mocks and spies, not just arbitrary objects.
I can't tell whether you still have this issue after subsequent updates, as it's impossible to read code that's embedded in comments.