Does setDefaultHighRepJobPolicyUnappliedJobPercentage(100) really work? - java

According to https://cloud.google.com/appengine/docs/java/tools/localunittesting#Writing_HRD_Datastore_Tests, "If your app uses the High Replication Datastore (HRD), you may want to write tests that verify your application's behavior in the face of eventual consistency. LocalDatastoreServiceTestConfig exposes options that make this easy." You're supposed to set setDefaultHighRepJobPolicyUnappliedJobPercentage(100) and then, "By setting the unapplied job percentage to 100, we are instructing the local datastore to operate with the maximum amount of eventual consistency. Maximum eventual consistency means writes will commit but always fail to apply, so global (non-ancestor) queries will consistently fail to see changes."
However, I don't think setDefaultHighRepJobPolicyUnappliedJobPercentage(100) works.
If it did, then my test case below, testEventualConsistency() should pass but it it fails on the second assertion. On the first assertion, I read back an object I've saved using an Objectify ancestor() query. It works as documented because the object is retrieved. However, the second assertion fails. In that assertion I've also read back the object I've saved but I haven't used an Objectify ancestor() query so it shouldn't retrieve anything because I've specified that no jobs should complete (i.e. the setDefaultHighRepJobPolicyUnappliedJobPercentage(100) setting).
EventualConsistencyTest Test Case
import static com.googlecode.objectify.ObjectifyService.begin;
import static com.googlecode.objectify.ObjectifyService.ofy;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import java.util.List;
import org.junit.Test;
import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
import com.googlecode.objectify.ObjectifyService;
import com.googlecode.objectify.Ref;
import com.googlecode.objectify.util.Closeable;
import com.netbase.followerdownloader.model.DownloadTask;
import com.netbase.followerdownloader.model.User;
public class EventualConsistencyTest {
private final LocalServiceTestHelper helper =
new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig()
.setDefaultHighRepJobPolicyUnappliedJobPercentage(100));
#Test
public void testEventualConsistency() {
helper.setUp();
ObjectifyRegistrar.registerDataModel();
User user = new User();
user.id = 1L;
Closeable closeable1 = begin();
ofy().save().entity(user);
closeable1.close();
Closeable closeable2 = begin();
DownloadTask downloadTask = new DownloadTask();
downloadTask.owner = Ref.create(user);
ofy().save().entity(downloadTask);
closeable2.close();
Closeable closeable3 = ObjectifyService.begin();
List<DownloadTask> downloadTasks1 = ofy().load().type(DownloadTask.class).ancestor(user).list();
assertThat(downloadTasks1.size(), equalTo(1));
closeable3.close();
Closeable closeable4 = ObjectifyService.begin();
List<DownloadTask> downloadTasks2 = ofy().load().type(DownloadTask.class).list();
assertThat(downloadTasks2.size(), equalTo(0)); // THIS SHOULD PASS IF setDefaultHighRepJobPolicyUnappliedJobPercentage(100) WORKED
closeable4.close();
helper.tearDown();
}
}
User Definition
import com.googlecode.objectify.annotation.Entity;
import com.googlecode.objectify.annotation.Id;
#Entity
public class User {
#Id public Long id;
public User () {
}
}
DownloadTask Definition
import com.googlecode.objectify.Ref;
import com.googlecode.objectify.annotation.Entity;
import com.googlecode.objectify.annotation.Id;
import com.googlecode.objectify.annotation.Parent;
#Entity
public class DownloadTask {
#Id public Long id;
#Parent public Ref<User> owner;
public DownloadTask() {
}
}
Environment:
appengine-api-1.0-sdk-1.9.17.jar
appengine-testing-1.9.17.jar
appengine-api-stubs-1.9.17.jar
junit-4.11.jar
objectify-5.1.3.jar
In case I missed anything else important, here is a more exhaustive list:
My questions are:
Is setDefaultHighRepJobPolicyUnappliedJobPercentage(100) broken?
Does setDefaultHighRepJobPolicyUnappliedJobPercentage(100) not really work as documented? Does it in fact apply the job even though the documentation says it's not supposed to?
Is the value passed to setDefaultHighRepJobPolicyUnappliedJobPercentage() really supposed to be 100 and not maybe let's say, 1.0f?
Do Objectify ancestor queries not really work as documented?

The problem is explained by an observation at https://cloud.google.com/appengine/docs/java/tools/localunittesting#Java_Writing_High_Replication_Datastore_tests :
"In the local environment, performing a get() of an Entity that belongs to an entity group with an unapplied write will always make the results of the unapplied write visible to subsequent global queries."
In this contect, this means the ancestor-query:
List<DownloadTask> downloadTasks1 = ofy().load().type(DownloadTask.class).ancestor(user).list();
which internally "performs a get() of an Entity that belongs to an entity group with an unapplied write" influences the behavior of the immediately-following global query:
List<DownloadTask> downloadTasks2 = ofy().load().type(DownloadTask.class).list();
To avoid your tests influencing each other, and in particular, interfering w/each other in this way, it's best to use a separate method per operation under test (each with all the needed setup and teardown parts), rather than having successive operations-under-test within a single test method.

Related

Binding instances during Caliper benchmarks

I've recently been tasked with benchmarking some features of our API, and I've been using Caliper to do so. It seems fairly straightforward and is actually quite powerful, I've been following the tutorials here:
How to use caliper
Tutorial from the creator
I'm working with Guice in our current app, so when I try to run the benchmark, I make sure to inject the services I need
Provided below is my code. I've tried setting the variables with their own #injected annotation, I've tried initiating them directly (although there's too many dependencies to deal with, and I'd have to initiate them as well). #Parms annotation won't work because I need to have a string type to iterate through (the parms only takes strings, there's documentation of what to do if it's another type, but it needs a .toString type method)
package com.~~~.~~~.api.benchmark;
import com.~~~.ds.mongo.orm.user.User;
import com.~~~.~~~.api.exceptions.auth.AccessDeniedException;
import com.~~~.~~~.api.service.authorization.UserService;
import com.~~~.~~~.api.service.campaign.CampaignMetadataService;
import com.google.caliper.BeforeExperiment;
import com.google.caliper.Benchmark;
import com.google.caliper.Param;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
public class CampaignBenchmark {
// === SERVICE INJECTIONS
#Inject
private CampaignMetadataService campaignMetadataService;
#Inject
private UserService userService;
// =============================================
// === BENCHMARK PARMS
#Param({
"7ca8c319",
"49191829"
})
String userId;
#Param({
"485",
"500"
})
String hashAdvertiserId;
// =============================================
// === TESTING PARMS
private User user;
// =============================================
// === SETUP
#Inject
public CampaignBenchmark(){
Injector injector = Guice.createInjector();
this.userService = injector.getInstance(UserService.class);
this.campaignMetadataService = injector.getInstance(CampaignMetadataService.class);
}
#BeforeExperiment
void setUp(){
this.user = userService.getUserByHashedId(userId);
}
// =============================================
// === BENCHMARKS
#Benchmark
int fetchAllCampaign(int reps) throws AccessDeniedException {
VideoIqUser user = this.user;
String hashAdvertiserId = this.hashAdvertiserId;
int dummy = 0;
for(int i=0 ; i<reps ; i++){
dummy |= campaignMetadataService.fetchAllCampaigns(user, hashAdvertiserId).size();
}
return dummy;
}
}
When we try to run it with
mvn exec:java -Dexec.mainClass="com.google.caliper.runner.CaliperMain" -Dexec.args="com.~~~.~~~.api.benchmark.CampaignBenchmark"
We get the following
WARNING: All illegal access operations will be denied in a future release
Experiment selection:
Benchmark Methods: [fetchAllCampaign]
Instruments: [allocation, runtime]
User parameters: {hashAdvertiserId=[485, 500], userId=[7ca8c319, 49191829]}
Virtual machines: [default]
Selection type: Full cartesian product
This selection yields 16 experiments.
Could not create an instance of the benchmark class following reasons:
1) Explicit bindings are required and com.~~~.~~~.api.service.campaign.CampaignMetadataService is not explicitly bound.
2) Explicit bindings are required and com.~~~.~~~.api.service.authorization.UserService is not explicitly bound.
The question is: at what point should I be doing injections, and how do I go about that? Should I have a wrapper class setup?
Quick Update
I forgot to mention that is part of a DropWizard (0.7.1) application. We use resources and inject them into the environment
Ex:
environment.jersey().register(injector.getInstance(CampaignManagementResource.class));
These resources contain the services needed to run them, and they are included as #Inject, though we never actually specify a binding anywhere else.
#Inject
private CampaignMetadataService apiCampaignMetadataService;
Is there something I should adjust for DropWizard, or should I just mock up the services?
Think of Guice as nothing but a Hashtable. Working with Guice has these parts:
creating the hashtable
putting things into it
getting things out of it
Your code creates the hashtable and queries it, but never puts anything in it:
public CampaignBenchmark() {
// Creating the hashtable
Injector injector = Guice.createInjector();
// Retrieving from the hashtable
this.userService = injector.getInstance(UserService.class);
this.campaignMetadataService = injector.getInstance(CampaignMetadataService.class);
}
The Guice hashtable is populated in Module classes. Undoubtedly, you have a CampaignModule or AdvertisingModule lying around somewhere. It probably looks like this:
public class CampaignModule extends AbstractModule {
#Override protected void configure() {
bind(CampaignMetadataService.class).to(CampaignMetadataServiceImplementation.class);
}
What that does is put a <CampaignMetadataService, CampaignMetadataServiceImplementation> entry into the Guice hashtable. Going forward, whoever asks for an instance of CampaignMetadataService receives an instance of CampaignMetadataServiceImplementation.
So in your code, you need to let Guice know about this module:
public CampaignBenchmark() {
// Creating the hashtable and letting modules populate it
Injector injector = Guice.createInjector(new CampaignModule(), new UserModule());
// Retrieving from the hashtable
this.userService = injector.getInstance(UserService.class);
this.campaignMetadataService = injector.getInstance(CampaignMetadataService.class);
}
Everything else you do is fine. Side note: #Inject annotations on your constructor and fields don't do anything, since you never ask Guice to supply you with instances of CampaignBenchmark. These can just be deleted.

JBehave how to persist objects state between steps

I am using JBehave for writing BDD Integration tests.
Problem: JBehave clears state of objects (instance variables) while executing individual steps
Code:
StepDefinition:
public class StepDefs {
private String str;
#Given("step represents a precondition to an $event")
public void given(String event){
str=event;
System.out.println("Given: "+str);
}
#When("step represents the occurrence of the event")
public void when() {
System.out.println("When: "+str);
}
#Then("step represents the outcome of the event")
public void then() {
}
}
Story:
Sample story
Narrative:
In order to communicate effectively to the business some functionality
As a development team
I want to use Behaviour-Driven Development
Scenario: A scenario is a collection of executable steps of different type
Given step represents a precondition to an event
When step represents the occurrence of the event
Then step represents the outcome of the event
JBehaveJUnitTestRunner:
#RunWith(JUnitReportingRunner.class)
public class JBehaveTestsRunner extends JUnitStories {
private CrossReference xref = new CrossReference();
public JBehaveTestsRunner() {
configuredEmbedder().embedderControls().doGenerateViewAfterStories(true).doIgnoreFailureInStories(true)
.doIgnoreFailureInView(true).doVerboseFailures(true);// .useThreads(1);
}
#Override
public Configuration configuration() {
Properties viewResources = new Properties();
viewResources.put("decorateNonHtml", "true");
return new MostUsefulConfiguration().useStoryLoader(new LoadFromClasspath(this.getClass().getClassLoader()))
.useStoryReporterBuilder(
new StoryReporterBuilder().withFormats(Format.HTML, Format.CONSOLE, Format.STATS)
.withViewResources(viewResources).withFailureTrace(true).withFailureTraceCompression(false)
.withCrossReference(xref));
}
#Override
public InjectableStepsFactory stepsFactory() {
return new ScanningStepsFactory(configuration(), "stepdefs");
}
#Override
public List<String> storyPaths() {
StoryFinder finder = new StoryFinder();
return finder.findPaths(CodeLocations.codeLocationFromClass(getClass()), Arrays.asList("**/Simple.story"), null);
}
}
Actual Output:
Processing system properties {}
Using controls EmbedderControls[batch=false,skip=false,generateViewAfterStories=true,ignoreFailureInStories=true,ignoreFailureInView=true,verboseFailures=true,verboseFiltering=false,storyTimeouts=300,threads=1,failOnStoryTimeout=false]
(BeforeStories)
Running story stories/Simple.story
Sample story
(stories/Simple.story)
Narrative:
In order to communicate effectively to the business some functionality
As a development team
I want to use Behaviour-Driven Development
Scenario: A scenario is a collection of executable steps of different type
**Given: event**
Given step represents a precondition to an event
**When: null**
When step represents the occurrence of the event
Then step represents the outcome of the event
(AfterStories)
Generating reports view to 'C:\WORKING\lunaworkspace\pkeautomation\target\jbehave' using formats '[html, console, stats, junitscenarioreporter]' and view properties '{decorateNonHtml=true}'
log4j:WARN No appenders could be found for logger (freemarker.cache).
log4j:WARN Please initialize the log4j system properly.
Reports view generated with 3 stories (of which 1 pending) containing 2 scenarios (of which 1 pending)
As can be seen in the output: In the Given step I am accepting a string argument which i am initializing it to instance variable "str", whilst printing the value to console I can see it successfully. But when the second step i.e When step executes I am getting null as the value of instance variable "str". How can I make JBehave to not clear state of objects after executing individual steps?
For anyone coming looking for an answer for this question I did found proper resolution to this by taking help from the JBehave google group community. The solution is quite simple instead of using ScanningStepFactory Use InstanceStepsFactory and that should persist the state of the objects. Link to the discussion: Google Group discussion
Snippet for anyone coming here for answer:
package runner;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import org.jbehave.core.configuration.Configuration;
import org.jbehave.core.configuration.MostUsefulConfiguration;
import org.jbehave.core.io.CodeLocations;
import org.jbehave.core.io.LoadFromClasspath;
import org.jbehave.core.io.StoryFinder;
import org.jbehave.core.junit.JUnitStories;
import org.jbehave.core.reporters.CrossReference;
import org.jbehave.core.reporters.Format;
import org.jbehave.core.reporters.StoryReporterBuilder;
//import org.jbehave.core.steps.CandidateSteps;
import org.jbehave.core.steps.InjectableStepsFactory;
import org.jbehave.core.steps.InstanceStepsFactory;
//import org.jbehave.core.steps.ScanningStepsFactory;
import org.junit.runner.RunWith;
import de.codecentric.jbehave.junit.monitoring.JUnitReportingRunner;
import stepdefs.StepDefs;
//import stepdefs.BarStep;
//import stepdefs.FooStep;
#RunWith(JUnitReportingRunner.class)
public class JBehaveTestsRunner extends JUnitStories {
private CrossReference xref = new CrossReference();
public JBehaveTestsRunner() {
configuredEmbedder().embedderControls().doGenerateViewAfterStories(true).doIgnoreFailureInStories(true)
.doIgnoreFailureInView(true).doVerboseFailures(true);// .useThreads(1);
}
#Override
public Configuration configuration() {
Properties viewResources = new Properties();
viewResources.put("decorateNonHtml", "true");
return new MostUsefulConfiguration().useStoryLoader(new LoadFromClasspath(this.getClass().getClassLoader()))
.useStoryReporterBuilder(new StoryReporterBuilder()
.withFormats(Format.HTML, Format.CONSOLE, Format.STATS).withViewResources(viewResources)
.withFailureTrace(true).withFailureTraceCompression(false).withCrossReference(xref));
}
/*#Override
public List<CandidateSteps> candidateSteps() {
return new InstanceStepsFactory(configuration(), new FooStep(), new BarStep(), new StepDefs())
.createCandidateSteps();
}*/
#Override
public InjectableStepsFactory stepsFactory() {
return new InstanceStepsFactory(configuration(), new StepDefs());
// return new ScanningStepsFactory(configuration(), "stepdefinitions");
}
#Override
public List<String> storyPaths() {
StoryFinder finder = new StoryFinder();
return finder.findPaths(CodeLocations.codeLocationFromClass(getClass()), Arrays.asList("**/Sample.story"),
null);
}
}
It's been a while since I used JBehave. It may be that you're creating a new ScanningStepsFactory for each stepsFactory() call. Try creating just one of those in the constructor then pass that instance back so that you're not creating a new one for each call.
And if that fails, try using an InstanceStepsFactory as in the example here:
public abstract class NoughtsAndCrossesStory extends JUnitStory {
public NoughtsAndCrossesStory() {
Configuration configuration = new MostUsefulConfiguration()
.useStoryPathResolver(new UnderscoredCamelCaseResolver(""))
.useStoryReporterBuilder(new StoryReporterBuilder()
.withCodeLocation(CodeLocations.codeLocationFromClass(this.getClass()))
.withDefaultFormats()
.withFormats(CONSOLE, TXT)
.withFailureTrace(true));
useConfiguration(configuration);
WindowControl windowControl = new WindowControl();
addSteps(new InstanceStepsFactory(configuration,new GridSteps(windowControl), new BeforeAndAfterSteps(windowControl)).createCandidateSteps());
}
}
You'll need to create some kind of persistent repository object in which to hold your string (in the example above, windowControl persists).
public class BeforeAndAfterSteps extends Steps {
private final WindowControl windowControl;
public BeforeAndAfterSteps(WindowControl windowControl) {
this.windowControl = windowControl;
}
#BeforeScenario
public void beforeScenarios() throws Exception {
windowControl.reset();
}
#AfterScenario
public void afterScenarios() throws Exception {
windowControl.destroy();
}
}
This allows you not only to persist state across steps, but between scenarios. Please note that that's generally considered a bad practice; I'm using this here to ensure that state is not persisted between scenarios, but in theory you could use it to, for instance, initialize default data before running your test suite.

How to test java code that uses Basho's riak-java-client?

I'm creating a small java service that returns a list of restaurants depending on the selected place.
Data is retrieved from Riak using com.basho.riak:riak-client:2.0.0 and the read operation is wrapped in a TenacityCommand.
Important classes are described below and I would be happy if you could assist me in creating a solid and simple unit test.
Commands are created using a factory:
package service.command.factory;
import com.basho.riak.client.api.RiakClient;
import com.basho.riak.client.api.commands.kv.FetchValue;
import com.basho.riak.client.core.query.Location;
import com.basho.riak.client.core.query.Namespace;
import domain.Place;
import service.command.FetchRestaurantsCommand;
public class FetchRestaurantsCommandFactory {
private final RiakClient riakClient;
private final Namespace namespace;
public FetchRestaurantsCommandFactory(final RiakClient riakClient, final Namespace namespace) {
this.riakClient = riakClient;
this.namespace = namespace;
}
public FetchRestaurantsCommand create(final Place place) {
Location location = new Location(namespace, place.getName());
FetchValue riakCommand = new FetchValue.Builder(location).build();
return new FetchRestaurantsCommand(riakClient, riakCommand);
}
}
And the command looks like this:
package service.command;
import java.util.Optional;
import service.command.keys.WhereToEatDependencyKeys;
import com.basho.riak.client.api.RiakClient;
import com.basho.riak.client.api.commands.kv.FetchValue;
import com.basho.riak.client.api.commands.kv.FetchValue.Response;
import com.yammer.tenacity.core.TenacityCommand;
import domain.Restaurant;
import domain.RestaurantList;
public class FetchRestaurantsCommand extends TenacityCommand<Optional<RestaurantList>>{
private final RiakClient riakClient;
private final FetchValue fetchValue;
public FetchRestaurantsCommand(RiakClient riakClient, FetchValue fetchValue) {
super(WhereToEatDependencyKeys.RIAK_GET_RESTAURANTS);
this.fetchValue = fetchValue;
this.riakClient = riakClient;
}
#Override
protected Optional<RestaurantList> run() throws Exception {
Response response = riakClient.execute(fetchValue);
return Optional.ofNullable(response.getValue(RestaurantList.class));
}
#Override
protected Optional<RestaurantList> getFallback() {
return Optional.of(RestaurantList.createFallback(new Restaurant("My failure suggestion")));
}
}
The above classes are used like:
Place place = // Created from url parameter
RiakClient riakClient = // created on start using the app's conf
Namespace namespace = // created on start using the app's conf
FetchRestaurantsCommandFactory factory = new FetchRestaurantsCommandFactory(riakClient, namespace);
FetchRestaurantsCommand command = factory.create(place);
return command.execute();
Apart from the features provided by TenacityCommand, how should I assert that my system fetches data as expeceted?
My initial idea was to mock a RiakClient to return a predefined FetchValue.Response and then make assertions on the resulting RestaurantList.
Unfortunately its not possible to instantiate or Mockito.mock a FetchValue.Response due to its design.
The accepted answer in How to mock riak java client? describes why Mockito won't work.
As far a I understood you want to write unit test. So you want to test that assuming some Response whether Optional<RestaurantList> instance is constructed correctly or not.
What I can think of is to wrap riakClient.execute(fetchValue); in a protected (or package private) helper function like:
Response fetch() {
return riakClient.execute(fetchValue);
}
Then in your test you can inherit from FetchRestaurantsCommand and override fetch function by returning any Response
Now, you can write any test to see whether the conversion of given Response to Optional<RestaurantList> behaves as expected or not.
If you need entire code and my explanation is not clear enough let me know to provide it.
I ended up using PowerMock as suggested by #gontard. See my unit test on GitHub: FetchRestaurantsCommandTest.java
I considered to create a fake/mock RiakClient in the com.basho.riak.client package. Such class could hopefully instantiate the Response object in the same way as the real client does. It would probably work for fetchValue but it would grow too big when involving more advanced Riak concepts s.a. siblings.

PowerMock:: [java.lang.IllegalStateException: no last call on a mock available]

To mock a static method powermock giving an exception while expect().
#Test
public void testRegistrarService()
{
mockStatic(IdGenerator.class);
expect(IdGenerator.generateNewId()).andReturn(42L);
long actualId=serTestObj.registerService();
replay(IdGenerator.class);
verify(IdGenerator.class);
assertEquals(42L,actualId);
}
public class ServiceRegistrator
{
public long registerService()
{
long id = IdGenerator.generateNewId();
return id;
}
}
public class IdGenerator
{
public static long generateNewId()
{
return System.currentTimeMillis();
}
}
Exception is:
java.lang.IllegalStateException: no last call on a mock available
at org.easymock.EasyMock.getControlForLastCall(EasyMock.java:521)
at org.easymock.EasyMock.expect(EasyMock.java:499)
at home.powermock.testServiceRegistrator.testRegistrarService(testServiceRegistrator.java:51)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at com.intellij.rt.execution.junit2.JUnitStarter.main(JUnitStarter.java:31)
how to mock staic method,while m using powerMock
i'm using intelliJ idea,how to resolve that exception.
Your code is missing the annotation
#PrepareForTest(IdGenerator.class)
In my case I was missing the following method in my test class
#ObjectFactory
/**
* Configure TestNG to use the PowerMock object factory.
*/
public IObjectFactory getObjectFactory() {
return new org.powermock.modules.testng.PowerMockObjectFactory();
}
Once I added it, I got rid of the "no last call on a mock available" error.
You need to put the replay before the actual call to the method.
EDIT: I think part of the problem may be caused because of your imports. Try not to import static powermock and static easymock (I've found that I often confuse myself and forget which one I need to call replay on).
Try running the following code. If it doesn't run correctly, then it may be because of a problem with the particular version of PowerMock/EasyMock/Junit that you have.
TestClass:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.easymock.EasyMock.*;
import static org.junit.Assert.*;
#RunWith(PowerMockRunner.class)
#PrepareForTest(IdGenerator.class)
public class TestClass {
#Test
public void testRegistrarService()
{
ServiceRegistrator serTestObj = new ServiceRegistrator();
PowerMock.mockStatic(IdGenerator.class);
expect(IdGenerator.generateNewId()).andReturn(42L);
PowerMock.replay(IdGenerator.class);
long actualId=serTestObj.registerService();
PowerMock.verify(IdGenerator.class);
assertEquals(42L,actualId);
}
}
IdGenerator:
public class IdGenerator {
public static long generateNewId()
{
return System.currentTimeMillis();
}
}
ServiceRegistrator:
public class ServiceRegistrator {
public long registerService()
{
long id = IdGenerator.generateNewId();
return id;
}
}
This question has been here for a long time but I'll try to give to it an aswer to explain what i did to resolve this problem.
First of all you have to use these two annotations:
#RunWith(PowerMockRunner.class)
This annotation let the current test class know what to use to run his tests, this is useful because we can use PowerMockRunner instead of JUnitRunner
#PrepareForTest(IdGenerator.class)
This annotation is used to prepare the class "IdGenerator" to be used in the test, prepare means that we will be able to mock the static methods as we do to the public methods
After added these two annotations we have to be sure we are using the right packages provided by PowerMock:
1) PowerMock:
Import: import org.powermock.api.easymock.PowerMock;
Use: We will use PowerMock to mock (and not only) our static method with the following code line
PowerMock.mockStatic(IdGenerator.class);
2) EasyMock:
Import: import org.easymock.EasyMock;
Use: We are going to use EasyMock to fake our object to be returned by our static method:
EasyMock.expect(IdGenerator.generateNewId()).andReturn(42L);
These was two examples on what are used PowerMock and EasyMock, and here I'll try to explain the code and what it does:
mockStatic(IdGenerator.class);
//We mock our IdGenerator class which have the static object
expect(IdGenerator.generateNewId()).andReturn(42L);
//We fake our method return object, when we'll call generateNewId()
//method it will return 42L
//With expecting we "record" our this method and we prepare it to be
//changed (it will return our decided value)
replay(IdGenerator.class);
//We go to perform our methods "registered" with the expect method
//inside the IdGenerator class, in this case with replay we just apply
//the changes of the expect to the method generateNewId()
long actualId = serTestObj.registerService();
//We create our object (which inside have a non static method that
//use generateNewId() static method)
verify(IdGenerator.class);
//We verify that the our faked method have been called
assertEquals(42L,actualId);
//We see if the two values are matching
Pay attention because replay must be used before you create the new object (actualId in this example) that will call the static faked methods.
Also do a lot of attention on what you are importing, for a distraction i was using
PowerMockito.mockStatic(className.class);
//from import org.powermock.api.mockito.PowerMockito;
Instead of
PowerMock.mockStatic(className.class);
//from import org.powermock.api.easymock.PowerMock;
I hope that this answer is clear and complete
By the way here i'll refer you to some useful links:
PowerMock Static Documentation on GitHub
Mvn Repository PowerMock Libraries
See you :D

Leaking this in constructor

The Controller class is a singleton, which seems to be a special case allowing for safely passing this to Controller.
Netbeans gives
Configure "passing suspicious parameters in the constructor" hint
for controller.addObserver(this); which makes me ask what the better technique would be, although I gather it's not a good approach.
package net.bounceme.dur.usenet.swing;
import java.util.Observable;
import java.util.Observer;
import java.util.logging.Logger;
import javax.mail.Folder;
import javax.swing.ListModel;
import net.bounceme.dur.usenet.controller.Controller;
import net.bounceme.dur.usenet.controller.MessageBean;
import net.bounceme.dur.usenet.controller.MessagesDefaultListModel;
public class MessageSelect extends javax.swing.JPanel implements Observer {
private static final Logger LOG = Logger.getLogger(MessageSelect.class.getName());
private Controller controller = Controller.getInstance();
private ListModel messages = new MessagesDefaultListModel();
private MessageBean messageBean = new MessageBean();
#SuppressWarnings("unchecked")
public MessageSelect() {
controller.addObserver(this);
initComponents();
messagesJList.setPrototypeCellValue("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
}
You are passing this to an external class (Controller) when the object hasn't been fully constructed. Controller could then reference your object while its construction hasn't finished.
Most people work around this by using a factory method which creates the object first, then passes this externally.
// private to force clients to use the static factory method
private MessageSelect() {
initComponents();
messagesJList.setPrototypeCellValue("xxx");
}
public static MessageSelect createInstance() {
MessageSelect instance = new MessageSelect();
instance.controller.addObserver(instance);
return instance;
}
Take a look at this excellent Brian Goetz article on safe object construction.
Using this as parameter can be dangerous in the contructor because the object is not fully initialized
As from http://wiki.netbeans.org/Java_Hints
I guess the point is, the super class may try and access apart of the class which has not yet been intialised (or you later change during your own construction)

Categories

Resources