I am trying to use PowerMockito to test a save method by verifying an internal audit() method call.
This internal call is made by auditor object which is being instantiated in an init() method of the class. As it is not injected I will not be able to mock it directly. When I used Mockito to verify it always said "There were zero interaction with the mock".
Question:How exactly do I test the save feature? Kindly help!
public class DaoImpl implements Dao{
private Auditor auditor;
#InjectValue
private ObjectLoader loader;
#InjectValue
private ConfigurationProvider confProvider;
#PostConstruct
public void init() {
//Mock this object instantiation and verify audit is called once
auditor = new SyncAuditor(confProvider.getClientConfiguration(), new EventRegProvider());
}
#Override
public void save(final AuditEvt auditEvt) {
final AuditedEvent auditedEvent = builder.build();
auditor.audit(auditedEvent);
}
Test :
#RunWith(PowerMockRunner.class)
#PrepareForTest({ DaoImplTest.class })
#PowerMockIgnore("javax.management.*")
public class DaoImplTest extends PowerMockito {
#InjectMocks
private DaoImpl dataAccess;
#Mock
private SynchAuditor auditorMock;
#Before
public void setUp() throws Exception {
loader = ObjectLoader.init("JUNIT");
loader.bind(ConfigurationProvider.class, configurationProviderMock);
dataAccess = loader.newInstance(DaoImpl.class);
}
#After
public void tearDown() {
loader.release(dataAccess);
ConnectionMgr.disconnect("JUNIT");
}
#Test
public void testSaveAuditEvent() throws Exception {
PowerMockito.whenNew(SynchAuditor.class).
withArguments(Matchers.any(ClientConfiguration.class), Matchers.any(EventRegProvider.class)).thenReturn(this.auditorMock);
final AuditEvent event = AuditEvent.from(null, "principal", UUID.randomUUID().toString(), "randomText",
new AuditEvtDefn((long) 522, "234242", "234242fdgd", true), SUCCESS, null, new GregorianCalendar());
dataAccess.save(event);
Mockito.verify(auditorMock, times(1)).audit(Matchers.any(AuditedEvent.class));
}
Even PowerMockito.verifyNew says there were zero interaction
PowerMockito.verifyNew(SynchronousAuditor.class,times(1)).withArguments(Matchers.any(AuditorClientConfiguration.class),Matchers.any(EventRegistrationProvider.class));
So, I figured out that java reflection will help in such a situation. You will have to get hold onto the real object and then set mocked object to it.
final Field privateAuditorField = DaoImpl.class.getDeclaredField("auditor");
privateAuditorField.setAccessible(true);
privateAuditorField.set(dataAccess, auditorMock);
Now verify will run sucessfully.
Mockito.verify(auditorMock, Mockito.times(1)).audit(Matchers.any(AuditedEvent.class));
Related
I am writing unit test cases for following class which extends WCMUsePOJO. Now, this class is using a getSlingScriptHelper method shown below.
public class ConstantsServiceProvider extends WCMUsePojo {
private static final Logger logger = LoggerFactory.getLogger(ConstantsServiceProvider.class);
private String var1;
#Override
public void activate() throws Exception {
ConstantsService constantsService = getSlingScriptHelper().getService(ConstantsService.class);
if(constantsService != null) {
var1 = constantsService.getVar1();
}
}
public string getVar1() { return var1; }
}
The question is how do I mock getSlingScriptHelper method? Following is my unit test code.
public class ConstantsServiceProviderTest {
#Rule
public final SlingContext context = new SlingContext(ResourceResolverType.JCR_MOCK);
#Mock
public SlingScriptHelper scriptHelper;
public ConstantsServiceProviderTest() throws Exception {
}
#Before
public void setUp() throws Exception {
ConstantsService service = new ConstantsService();
scriptHelper = context.slingScriptHelper();
provider = new ConstantsServiceProvider();
provider.activate();
}
#Test
public void testGetvar1() throws Exception {
String testvar1 = "";
String var1 = provider.getVar1();
assertEquals(testvar1, var1);
}
}
The only thing that you should "have to"* mock is the SlingScriptHelper instance itself, so that it will mimic the dependency injection of the declared service.
Everything else (e.g. the Bindings instance) can be a concrete implementation, for example:
import org.apache.sling.api.scripting.SlingBindings;
import org.apache.sling.api.scripting.SlingScriptHelper;
import org.junit.Test;
import javax.script.Bindings;
import javax.script.SimpleBindings;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class ConstantsServiceProviderTest {
private SlingScriptHelper mockSling = mock(SlingScriptHelper.class);
private ConstantsServiceProvider constantsServiceProvider = new ConstantsServiceProvider();
private Bindings bindings = new SimpleBindings();
#Test
public void testFoo() throws Exception {
//Arrange
final String expected = "Hello world";
final ConstantsService testConstantsService = new TestConstantsService(expected);
when(mockSling.getService(ConstantsService.class)).thenReturn(testConstantsService);
bindings.put(SlingBindings.SLING, mockSling);
//Act
constantsServiceProvider.init(bindings);
//Assert
final String actual = constantsServiceProvider.getVar1();
assertThat(actual, is(equalTo(expected)));
}
class TestConstantsService extends ConstantsService {
String var1 = "";
TestConstantsService(String var1) {
this.var1 = var1;
}
#Override
String getVar1() {
return var1;
}
}
}
The entry point here, as you said above, is via the init() method of the WCMUsePojo superclass (as this method is an implementation of the Use.class interface, this test structure also works for testing that via that interface, even if you don't use WCMUsePojo directly.)
*this could be any type of test-double, not necessarily a mock.
You shouldn't create a mock for ConstantsServiceProvider.class if you want to unit-test it. Instead, you should create mocks of its internal objects. So:
Create real instance of ConstantsServiceProvider with new
Mock objects that are returned by getSlingScriptHelper().getService(.) methods. Usually, dependencies are provided (injected) to classes by some container like Spring or simply provided by other classes of your app using setters. In both cases mocks creation is easy.
If your current implementation doesn't allow this - consider refactoring.
You are testing void activate() method which doesn't return anything. So, you should verify calling constantsService.getVar1() method.
I strongly advice you to study Vogella unit-testing tutorial
Here one of possible solution.
The main idea is to have a real object of your class but with overridden getSlingScriptHelper() to return mocked scriptHelper.
I mocked the ConstantsService as well but may be not needed, I don't know your code.
public class ConstantsServiceProviderTest {
#Mock
public SlingScriptHelper scriptHelper;
#Test
public void getVar1ReturnsActivatedValue() throws Exception {
// setup
final String expectedResult = "some value";
// Have a mocked ConstantsService, but if possible have a real instance.
final ConstantsService mockedConstantsService =
Mockito.mock(ConstantsService.class);
Mockito.when(
mockedConstantsService.getVar1())
.thenReturn(expectedResult);
Mockito.when(
scriptHelper.getService(ConstantsService.class))
.thenReturn(mockedConstantsService);
// Have a real instance of your class under testing but with overridden getSlingScriptHelper()
final ConstantsServiceProvider providerWithMockedHelper =
new ConstantsServiceProvider() {
#Override
SlingScriptHelper getSlingScriptHelper() {
return scriptHelper;
}
};
// when
String actualResult = providerWithMockedHelper.getVar1();
// then
assertEquals(expectedResult, actualResult);
}
}
I have multiple #Test method in a class while running the paxexam it fails with the below Exception
java.lang.Exception: No runnable methods
at org.junit.runners.BlockJUnit4ClassRunner.validateInstanceMethods(BlockJUnit4ClassRunner.java:169)
at org.junit.runners.BlockJUnit4ClassRunner.collectInitializationErrors(BlockJUnit4ClassRunner.java:104)
at org.junit.runners.ParentRunner.validate(ParentRunner.java:355)
at org.junit.runners.ParentRunner.<init>(ParentRunner.java:76)
at org.junit.runners.BlockJUnit4ClassRunner.<init>(BlockJUnit4ClassRunner.java:57)
at org.ops4j.pax.exam.invoker.junit.internal.ContainerTestRunner.<init>(ContainerTestRunner.java:54)
at org.ops4j.pax.exam.invoker.junit.internal.ContainerTestRunnerBuilder.runnerForClass(ContainerTestRunnerBuilder.java:48)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
at org.ops4j.pax.exam.invoker.junit.internal.ContainerTestRunnerClassRequest.getRunner(ContainerTestRunnerClassRequest.java:61)
at org.junit.internal.requests.FilterRequest.getRunner(FilterRequest.java:31)
at org.junit.runner.JUnitCore.run(JUnitCore.java:138)
The below is the pax exam code. When i run this code i get an exception. Adding one more point if i change this annotation #ExamReactorStrategy(PerClass.class) to #ExamReactorStrategy(PerMethod.class) this will work the problem is test container restarts after every method
#RunWith(PaxExam.class)
#ExamReactorStrategy(PerClass.class)
public class Integration5TestCases {
private static Logger LOG = LoggerFactory.getLogger(IntegrationTestCases.class);
#Inject
private BundleContext bc;
#Inject
protected FeaturesService featuresService;
/**
* To make sure the tests run only when the boot features are fully
* installed
*/
#Inject
BootFinished bootFinished;
#Configuration
public static Option[] configuration() throws Exception {
MavenUrlReference oracleLib = maven()
.groupId("com.oracle")
.artifactId("ojdbc6")
.version("11.2.0")
.type("jar");
MavenUrlReference dbHandler = maven().groupId("Oracle")
.artifactId("DBHandler")
.versionAsInProject()
.type("xml")
.classifier("features");
return new Option[] {
returnNewKarafInstance(),
systemProperty(PaxExamConstants.ORCALESYSPROPNAME).value(dbHandler.getURL()),
KarafDistributionOption.debugConfiguration("8898", true),
bootClasspathLibrary(oracleLib),
configureConsole().ignoreLocalConsole(),
logLevel(LogLevel.INFO),
keepRuntimeFolder(),
};
}
private static KarafDistributionBaseConfigurationOption returnNewKarafInstance(){
return karafDistributionConfiguration().frameworkUrl(maven().groupId("org.apache.karaf").artifactId("apache-karaf")
.type("zip").versionAsInProject())
.unpackDirectory(new File("target/paxexam/unpack/"))
.useDeployFolder(false);
}
#Inject
SessionFactory commandProcessor;
#Test
public void test1() throws Exception {
System.out.println("sd");
}
#Test
public void test2() throws Exception {
System.out.println("sd");
}
}
This was happening because junit lib was initialized twice inside the karaf container. Thanks for the help guys.
I am still learning JMockit and need help understanding it.
I am testing a class that uses superclass methods. My test gets a null pointer when it attempts to use the superclass method due to code inside it that uses struts action context to get the session and pull an object from the session.
The method I want to bypass the struts session stuff inside the protected method.
public class MyExtendingClass extends MySuperClass{
public void methodIamTesting(){///}
}
public abstract class MySuperClass{
//I want to mock this method
protected Object myProtectedSuperClassMethod(){
// struts action context code that returns an object//}
}
Test code
#Test
public void testRunsAndDoesntPass() {
Mockit.setUpMock(MySuperClass.class, new MySuperClass(){
public Object myProtectedSuperClassMethod() {
return object;
}
});
// real class method invocation happens
assertEquals(expected, actual);
}
I keep getting NullPointers just like if I didn't have the mock
Not sure what to try next. All the docs and code samples I have read say to just declare the superclass method as public in the setUpMock and it should work.
I can't mock the entire class because that is the class I am testing.
I discovered that I needed to create the MockClass then reference it using setupmock correctly.
I am really falling in love with JMockit.
#MockClass(realClass = MyExtendingClass.class)
public static class MockSuperClass {
final Object object = new Object();
#Mock
public Object myProtectedSuperClassMethod() {
return object;
}}
#Test
public void testRunsAndNowWillPass() {
Mockit.setUpMock(MySuperClass.class, new MockSuperClass(){
public Object myProtectedSuperClassMethod() {
return object;
}});
// real class method invocation happens where i set expected and actual
assertEquals(expected, actual);
}
you mask the parent class implementation out totally #Mocked final MySuperClass base
abstract class MySuperClass{
protected Object myProtectedSuperClassMethod(){
}
class MyExtendingClass extends MySuperClass{
public void methodIamTesting(){///}
}
#Test
public void testRunsAndDoesntPass(#Mocked final MySuperClass base ) {
//you could mask out all the base class implementation like this
new Expectations(){{
invoke(base, "myProtectedSuperClassMethod");
}};
// real class method invocation happens
// ...
assertEquals(expected, actual);
}
The title pretty much says it all. I would like to set up a traditional JUnit test to mock a controller's dependencies and run tests against actions.
I've found that I can achieve my goal like this:
public class AccountsControllerTest {
private controllers.Accounts accountsController;
#Test
public void test() {
running(fakeApplication(), new Runnable() {
public void run() {
accountsController = new controllers.Accounts();
accountsController.setAccountsWorkflow(mock(workflow.Accounts.class));
}
});
}
}
The obvious problem here is that I'm instantiating my class under test and injecting mock dependencies from the test method itself, when I should be doing that in the setup() method. It seems that the setup() method is useless if I'm going to test my controller in a traditional way.
Of course I can test controllers the way Play recommends, but my application is dependent on an external SOAP web service, so I need unit tests to show that our code is working when their servers are down.
So, what's the best way to unit test a Play controller using mocks while still taking advantage of setup() and teardown() methods?
Edit
I realize I'm assuming some knowledge here, so for those who are unaware, controller instantiation in a unit test must be wrapped in a running() function or Play! will throw a runtime exception saying that no application has been started.
You could accomplish this using Mockito and Play's FakeApplication and setting the static Http.Context variable.
This way you can write the test like all other JUnit test.
Example:
...
import static play.test.Helpers.status;
import play.test.FakeApplication;
import play.test.Helpers;
import play.mvc.Http;
import play.mvc.Result;
...
#RunWith(MockitoJUnitRunner.class)
public class ApplicationTest {
public static FakeApplication app;
#Mock
private Http.Request request;
#BeforeClass
public static void startApp() {
app = Helpers.fakeApplication();
Helpers.start(app);
}
#Before
public void setUp() throws Exception {
Map<String, String> flashData = Collections.emptyMap();
Http.Context context = new Http.Context(request, flashData, flashData);
Http.Context.current.set(context);
}
#Test
public void testIndex() {
final Result result = Application.index();
assertEquals(play.mvc.Http.Status.OK, status(result));
}
#AfterClass
public static void stopApp() {
Helpers.stop(app);
}
I have simple code:
public interface AccountService {
public boolean verifyBalance(AccountInfo account);
}
public class MoneyTransferServiceBean implements MoneyTransferService {
private AccountService accountService;
class MoneyTransfer {
private TransferRequest request;
public MoneyTransfer(TransferRequest request) {
this.request = request;
}
private void verifySrcBalance() throws TransferException {
if (!accountService.verifyBalance("request")
throw new TransferException("LOW_BALANCE_ERROR_MESSAGE");
}
}
}
How Im make implement dummy for accountService.verifyBalance()
Im trying this:
private MoneyTransferServiceBean moneyTransferService;
AccountService mockedAccountService = mock(AccountService.class);
doReturn(true).when(mockedAccountService).verifyBalance("request");
MoneyTransfer moneyTransfer = moneyTransferService.new MoneyTransfer(transferRequest);
moneyTransfer.verifySrcBalance();
But this does not take effect.
generaly doX() methods are used for mocking exception throws and void methods.
Other use is mocked by when([method_call]).thenX();
First create mocks and put your mock into tested service with setters or Whitebox:
MoneyTransferServiceBean moneyTransferService = new MoneyTransferServiceBean();
AccountService mockedAccountService = mock(AccountService.class);
Whitebox.setInternalState(moneyTransferService , "accountService", mockedAccountService);
You should mock interaction with the mock like this:
when(mockedAccountService.verifyBalance(eq(accInfo)).thenReturn(true);
verify(mockedAccountService).verifyBalance(accInfo);
verifyNoMoreInteractions(mockedAccountService);
There are nice examples on Mockito site explaining it all.