Unit testing with final classes of AWS SDK - java

I have written following code to publish some metrics around AWS Step function (its java lambda for aws)
#Override
public void handleRequest(InputStream input, OutputStream output, Context context) throws IOException {
int inProgressStateMachines = 0;
LocalDateTime now = LocalDateTime.now();
long alarmThreshold = getAlarmThreshold(input, context.getLogger());
AWSStepFunctions awsStepFunctions = AWSStepFunctionsClientBuilder.standard().build();
ListStateMachinesRequest listStateMachinesRequest = new ListStateMachinesRequest();
ListStateMachinesResult listStateMachinesResult = awsStepFunctions.listStateMachines(listStateMachinesRequest);
for (StateMachineListItem stateMachineListItem : listStateMachinesResult.getStateMachines()) {
ListExecutionsRequest listExecutionRequest = new ListExecutionsRequest()
.withStateMachineArn(stateMachineListItem.getStateMachineArn())
.withStatusFilter(ExecutionStatus.RUNNING);
ListExecutionsResult listExecutionsResult = awsStepFunctions.listExecutions(listExecutionRequest);
for (ExecutionListItem executionListItem : listExecutionsResult.getExecutions()) {
LocalDateTime stateMachineStartTime = LocalDateTime.ofInstant(
executionListItem.getStartDate().toInstant(), ZoneId.systemDefault());
long elapsedTime = ChronoUnit.SECONDS.between(stateMachineStartTime, now);
if (elapsedTime > alarmThreshold){
inProgressStateMachines++;
}
}
publishMetrics(inProgressStateMachines);
}
}
Now I am trying to unit-test this method and having some issues.
First of all, I get error that Mockito can not mock final class when i tried to mock AWSStepFunctionsClientBuilder.
Secondly, I have private methods which are being called with specific params.
The question is
How can i unit test this code? I read it somewhere that if a code isn't unit-testable then its a bad design. How can i improve this code so that its easily testable? I would prefer to keep those helper methods as private methods.
How can i mock final objects from AWS SDK to test this code? I can not use any other framework but Mockito.

You actually don't want to mock AWSStepFunctionsClientBuilder because you are actually calling AWSStepFunctions, which you'll have to mock anyway even after mocking the builder.
So make AWSStepFunctions an instance variable:
// add appropriate getter/setter as well
private AWSStepFunctions awsStepFunctions;
Where you currently call the builder to initialize awsStepFunctions, change to:
if (awsStepFunctions == null)
awsStepFunctions = AWSStepFunctionsClientBuilder.standard().build();
Now, during unit test, you can set awsStepFunctions to a mocked instance, bypassing the conditional initialization above.
[Edit] Some more thoughts based on #kdgregory's comment below:
The answer above is meant to provide a solution given the existing code structure, without requiring any major refactoring. In general though, ideally you would want to move the bulk of the code into another plain, more testable Java class, where you can properly inject dependencies, manage life cycles, etc.

Related

Integration test an API whose behavior depends on the current time

I have a few APIs I'm trying to thoroughly integration test -- I'm hitting the remote service which is running in a test environment (not the same box that is running the tests, the tests make real service calls), I can't just use dependency injection to solve all my problems. We already have a good suite of unit tests on these classes.
The API I'm testing is SaveThingy. It saves a Thingy if it's valid, and returns you the id of it. One of the checks is that you can only save a thingy at certain times, say only on weekdays. If you call SaveThingy on the weekend, it insults you personally instead of saving a Thingy. The implementation looks something like the following
ThingyId saveThingy(Thingy thingy) {
if (isWeekend(LocalDate.now().getDayOfWeek())) {
throw new PersonalInsultException("your mother wears army boots");
}
return thingyDao.save(thingy);
}
I'd ideally like to have both cases tested each time we run integration tests, without any waiting. In some code, I want tests similar to the following to run each time.
#Test
public void saveThingy_validThingyOnWeekday_savesThingy() {
ThingyId id = serviceUnderTest.saveThingy(THINGY);
assertThat(serviceUnderTest.getThingyById(id)).isEqualTo(THINGY);
}
#Test(expected = PersonalInsultException.class)
public void saveThingy_validThingyOnWeekend_receivePersonalInsult() {
serviceUnderTest.saveThing(THINGY);
}
Are there any standard ways that allow complete testing of such APIs? I've considered a few options (below), but wanted to get additional opinions.
say no to integration testing, live with only unit tests for these APIs
change the remote clock, either using a private API or by literally ssh-ing into the host before running each test
write tests that are time dependent; only testing one of the possible behaviors, or testing one behavior then sleeping until other conditions are met
invent dummy data that will always save or always throw an exception
I suppose in your ThingyService class you have a public
or protected isWeekend method. Probably something like this:
public boolean isWeekend(DayOfWeek dayOfWeek) {
return dayOfWeek == DayOfWeek.SATURDAY || dayOfWeek == DayOfWeek.SUNDAY;
}
In your ThingyServiceTest you can then create two specialized ThingyService instances with mocked isWeekend methods.
In your test-cases you can use either of these:
// service with weekday behavior
private ThingyService serviceUnderTest_weekday = new ThingyService() {
#Override
public boolean isWeekend(DayOfWeek dayOfWeek) {
return false;
}
};
// service with weekend behavior
private ThingyService serviceUnderTest_weekend = new ThingyService() {
#Override
public boolean isWeekend(DayOfWeek dayOfWeek) {
return true;
}
};
#Test
public void saveThingy_validThingyOnWeekday_savesThingy() {
ThingyId id = serviceUnderTest_weekday.saveThingy(THINGY);
assertThat(serviceUnderTest_weekday.getThingyById(id)).isEqualTo(THINGY);
}
#Test(expected = PersonalInsultException.class)
public void saveThingy_validThingyOnWeekend_receivePersonalInsult() {
serviceUnderTest_weekend.saveThing(THINGY);
}
You are trying to achieve black box testing with white box testing requirements: it's simply not possible. Stick to white box testing and mock out your DateProvider locally. Maybe not what you want to hear but you will waste so much time otherwise trying to align the stars to produce the output you want in your assertion.
Now on the other hand if you really want to do this run your application inside a docker container and change the system clock then just tear it down between tests.
Alternatively open up a separate endpoint which allows to specify the current time via your service and only deploy this endpoint when you are testing. Or have a configuration interface responsible for determining the source of your current time and when you deploy to your test environment configure the app accordingly.
Instead of using LocalDate.now() or Instant.now() or Whatever.now() or passing long timestamps, consider adding java.time.Clock field to your class, and either add an initialization parameter to constructor or provide a setter.
Clock.instant() is essentially Instant.now(), and you can convert the instant into any other temporal class.
In production, you will use Clock.systemUTC() as the value of that field.
In some tests, you can use Clock.fixed(), and in all tests you can just mock the way you need it for tests.
This approach is mostly suited for unit tests. You can still inject your custom Clock implementation in integration environment, so that the application as a whole will think that the current time is whatever you need.

What methods should I have JUnit tests for - How to mock methods with many dependencies

I am new to JUnit, and do not know which methods should have tests and which should not. Take the following example:
public List<Site> getSites(String user)
{
SiteDao dao = new SiteDaoImpl();
List<Site> siteList = new ArrayList<Site>();
ServiceRequest rq = new ServiceRequest();
rq.setUser(user);
try
{
ServiceResponse response = siteDAO.getReponse(rq);
List<String> siteNums = response.getSiteNums();
if (siteNums != null && !siteNums.isEmpty())
{
List<DbModelSite> siteInfo = dao.getSiteInfo(siteNums);
if (siteInfo != null && !siteInfo.isEmpty())
{
siteList = SiteMapper.mapSites(siteInfo);
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
return siteList;
}
public static List<Site> mapSites(List<DbModelSite> siteInfo)
{
List<Site> siteList = null;
if (siteInfo != null && !siteInfo.isEmpty())
{
siteList = new ArrayList<Site>();
for (DbModelSite temp : siteInfo)
{
Site currSite = mapSite(temp);
siteList.add(currSite);
}
}
return siteList;
}
public static Site mapSite(DbModelSite site)
{
Site mappedSite = null;
if (site != null)
{
mappedSite = new Site();
mappedSite.setSiteNum(site.getSiteNum());
mappedSite.setSpace(site.getSpace());
mappedSite.setIndicator("Y");
}
return mappedSite;
}
It is pretty trivial to come up with a unit test for both the mapSites() and mapSite()methods, but where I am having trouble is with the getSites() method. Does it make sense to unit test this method? If so, how would I go about doing so? It seems that this would require quite a bit of mocking, and as I am very new to JUnit, I have not been able to figure out how to mock all of these objects.
So my question is really two fold:
How do you determine if a method needs to be unit tested?
How does one unit test a complex method which requires a large amount of mocking?
Yes, it makes sense to test that method.
The first thing to be able to test it, would be to use dependency injection. If the method creates its own SiteDao instance using new, there is no way you can tell the method to use another, mock instance of SiteDao.
So, read on dependency injection, and use it. Basically, it boils down to
public class MyService {
private SiteDao siteDao;
public MyService(SiteDao siteDao) {
this.siteDao = siteDao;
}
// use the siteDao passed when constructing the object, instead of constructing it
}
That way, when testing your service, you can do
SiteDao mockSiteDao = mock(SiteDao.class);
SiteService service = new SiteService(mockSiteDao);
Here's one pice of advice that is not directly related to your question, but will make your code much simpler, and thus easier to test, too:
Never return null from a method returning a collection. Return an empty collection to signal "no element".
In general, don't accept null as a valid method argument value, especially if the argument is a collection.
Corollary of 1 and 2: by following these principles, you never need to check for null or emptyness of a collection. Just use it directly.
This will reduce the number of if (siteNums != null && !siteNums.isEmpty()) cluttering your code, and you'll have way fewer branches to test, too.
Note that all sane libraries (the JDK methods, JPA, etc.) follow these principles. A JPA query will never return a null list for example.
Also, don't swallow an exception by just printing its stack trace and returning an empty list, as if nothing bad happened. Let the exception propagate so that you can notice and fix the bug.
Just imagine that this method is a method returning the number of cancer tumors found by a medical analysis system. Would you really like the system to tell you that you're in perfect health, whereas the system was in fact unable to do its job due to an exception? I would really prefer the system to say "I'm out of order, use another machine to be sure".
The idea of unit testing is to ensure that each "unit" (which is usually a method) can be tested in isolation so you can test that for given input you receive an expected output, so to answer your questions:
I should say all public methods should be unit tested
If you are doing too much in your method that you need to mock lots then you probably want to break the functionality out into another class
Going back to your example there are a couple of things to be wary of if you want to unit test:
new - anytime you use this keyword in a method you will find it difficult to mock that object. In some cases (like ServiceRequest) it's fine but in others such as SiteDao you'll have problems.
Static methods - same thing, with SiteMapper.mapSites(siteInfo) you will find it difficult to mock
You can use libraries such as PowerMock to mock new, private and static methods but I personally try to avoid that.

Writing testable code when new object is being constructed using Mockito only

So I am writing a class which I want to follow the best practices and be testable.
I have a new object to be created inside it. So, I am following the factory pattern to achieve it.
public class Apple {
// factory object injected in class
private SeedFactory seedFactory;
// Method to be tested
public void myMethod(String property1, int property2, String depends) {
// Just to set the necessary parameter
seedFactory = new SeedFactory(property1, property2);
// Factory pattern intact. Instance generation depends on only one parameter
SeedFactory result = seedFactory.getInstance(depends);
}
}
EDIT: Adding code for factory as well.
public class SeedFactory{
String property1;
int property2;
SeedFactory(property1,property2){
this.property1 = property1;
this.property2 = property2;
}
SeedFactory getInstance(int depends){
if(depends == 1)
{ // do stuff }
else{ // do stuff and return instance }
Now, before I actually create the new object, I have to make sure that I set two properties for the new instance to be generated, which are needed to be present irrespective of the type of instance generated by the factory. depends is the actual parameter which tells the factory what instance to return.
Now, as far as testability of this code is concerned, I can user PowerMockito to mock the factory object using whenNew but using PowerMockito is not a choice. I have to make it testable without it.
Also, I have tried to encapsulate the new call within a one line function and then use spy. But I want to avoid using spy, since it is not considered a good practice, in context of where this code is being used as a whole.
So my question is, Is there any way, without using PowerMockito, to re-write this class so that it can be unit tested properly?
If the instance to be generated needed only one parameter, then it would have been trivial. However, I don't want to pass more than one parameter to getInstance().
SeedFactory is not Apple's dependancy but your method depends on SeedFactory which has "uses" relationship. So to define proper relation i would suggest you use "USES" relation as below:
public void myMethod(SeedFactory seedFactory, String depends){ // Method to be tested
Now you could mock SeedFactory and can unit test it appropriately.
I think you're doing something wrong.
If SeedFactory isn't an Apple's dependency but an internal concern, hence you don't need to mock a SeedFactory to test Apple. You should test the public API provided by Apple only.
If SeedFactory is an Apple's dependency, so it definitely should be injected.

How to find number of times static function is called Mockito

I am having a function like the following.
public String getDecodedToken() throws UnsupportedEncodingException {
if (token == null) {
String token = ClassContainingStatic
.findString("static");
this.token = new String(Base64.decodeBase64(token), "UTF-8");
}
return token;
}
To test the function, I do not want to mock the ClassContainingStatic class because it will render the test useless. Rather I would like to see that if the call happened to ClassContainingStatic.findString("static") without mocking the object. Is there a way to achieve number of function call made to the real object?
Certainly possible with a bit of refactoring. If you extract the call to the static class in a separate method:
public String getDecodedToken() throws UnsupportedEncodingException{
if( token == null ){
token = createToken();
}
return token;
}
String createToken() throws UnsupportedEncodingException{
String token = ClassContainingStatic.findString("static");
return new String( Base64.decodeBase64(token), "UTF-8" );
}
Now you can create a mock or spy, and simply verify whether the method is called.
ClassUnderTest spy = Mockito.spy( new ClassUnderTest() );
String token = spy.getDecodedToken();
Mockito.verify( spy ).createToken();
I assumed the "static" string is fixed. If not, pass it as a parameter to the createToken class, and then you can adjust the verify accordingly.
I might have made a mistake in the Mockito syntax, but the general idea should be clear. Only drawback is that you need to create a package visible/protected (or even public if you want, but generally that is not the case) method so that the verify call can be made.
The basic thing you need here is called a spy in Mockito language.
While a mock is a completely new object, a spy wraps an existing instance and forwards calls to its methods to the original object by default, while at the same time supports mocking of method calls or verifying of calls.
But you have another challenge: the method you want to verify seems to be a static method. With Mockito you can't mock static methods. You have two basic options:
Refactor so that the method is no longer static and you provide the object which hosts the method on as a parameter to the constructor. This parameter then can be a mock or spy.
Use PowerMock to mock static methods. I would only accept the usage of PowerMock in legacy projects, where one needs to create tests with as little refactorng as possible. PowerMock is poerful yet clumsy, slow and prone to causing problems down the road, e.g. by creating lots of classes on the fly resulting in PermGen issues.

Working with Injectable Singletons

I recently stumbled upon this interesting concept that may save me much testing efforts.
What I do not understand is how can the provider be injected in runtime?
The scenario is trivial: I am constructing a mock object at run-time with my mocking framework of choice, but I do not know the name of the generated class in advance because it is a mock (so I can't configure it in advance, not do I want to).
Did anybody make successful use of this technique in unit tests?
Thank you.
The concept described in that article is an Ambient Context that uses a Service Locator in the background.
Because of the use of a static property and the use of the Service Locator, this pattern is very inconvenient for unit testing. To be able to run a test that verifies code that uses this singleton, you need to set up a valid Service Locator and configure it with the singleton (probably a mock instance) that you care about using testing.
Even the example given by the article already suffers from these problems, since the "Do you like singletons?" code, is hard to test:
if (DialogDisplayer.getDefault().yesOrNo(
"Do you like singletons?"
)) {
System.err.println("OK, thank you!");
} else {
System.err.println(
"Visit http://singletons.apidesign.org to"
+ " change your mind!"
);
}
A better alternative is to use constructor injection to inject that singleton (please excuse my French, but I'm not a native Java speaker):
public class AskTheUserController
{
private DialogDisplayer dialogDisplayer;
private MessageDisplayer messageDisplayer;
public AskTheUserController(DialogDisplayer dialogDisplayer,
MessageDisplayer messageDisplayer)
{
this.dialogDisplayer = dialogDisplayer;
this.messageDisplayer = messageDisplayer;
}
public void AskTheUser()
{
if (this.dialogDisplayer.yesOrNo(
"Do you like singletons?"
)) {
this.messageDisplayer.display("OK, thank you!");
} else {
this.messageDisplayer.display(
"Visit http://singletons.apidesign.org to"
+ " change your mind!"
);
}
}
}
There was another 'hidden' dependency in that code: System.err.println. It got abstracted using a MessageDisplayer interface. This code has a few clear advantages:
By injecting both dependencies, the consumer doesn't even need to know that those dependencies are singletons.
The code clearly communicates the dependencies it takes.
The code can easily be tested using mock objects.
The test code doesn't need to configure a service locator.
Your tests might look like this:
#Test
public void AskTheUser_WhenUserSaysYes_WeThankHim()
{
// Arrange
bool answer = true;
MockMessageDisplayer message = new MockMessageDisplayer();
MockDialogDisplayer dialog = new MockDialogDisplayer(answer);
AskTheUserController controller =
new AskTheUserController(dialog, message);
// Act
controller.AskTheUser();
// Assert
Assert.AreEqual("OK, thank you!", message.displayedMessage);
}
#Test
public void AskTheUser_WhenUserSaysNo_WeLetHimChangeHisMind()
{
// Arrange
bool answer = true;
MockMessageDisplayer message = new MockMessageDisplayer();
MockDialogDisplayer dialog = new MockDialogDisplayer(answer);
AskTheUserController controller =
new AskTheUserController(dialog, message);
// Act
controller.AskTheUser();
// Assert
Assert.IsTrue(
message.displayedMessage.contains("change your mind"));
}
Your test code will never be as intend revealing as the code above when you're using the 'injectable singleton' pattern as shown in the article.
There is nothing wrong with singletons, which are useful and necessary concepts in any software. The problem is that you shouldn't implement them with static fields and methods.
I use Guice to inject my singletons and I haven't had to use static in my code base and tests in a very long time.
Here are a couple of links you might find useful that explain how to achieve testable singletons with Guice:
Rehabilitating the Singleton pattern.
Guice and TestNG

Categories