Can Selenium take a screenshot on test failure with JUnit? - java

When my test case fails, especially on our build server, I want to take a picture / screenshot of the screen to help me debug what happened later on. I know how to take a screenshot, but I was hoping for a way in JUnit to call my takeScreenshot() method if a test fails, before the browser is closed.
No, I don't want to go edit our bazillions of tests to add a try/catch. I could maybe, just possibly be talked into an annotation, I suppose. All of my tests have a common parent class, but I can't think of anything I can do there to solve this.
Ideas?

A few quick searches led me to this:
http://blogs.steeplesoft.com/posts/2012/grabbing-screenshots-of-failed-selenium-tests.html
Basically, he recommends creating a JUnit4 Rule that wraps the test Statement in a try/catch block in which he calls:
imageFileOutputStream.write(
((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES));
Does that work for your problem?

If you want to quickly add this behavior to ALL your tests in the run you can use the RunListener interface to listen for test failures.
public class ScreenshotListener extends RunListener {
private TakesScreenshot screenshotTaker;
#Override
public void testFailure(Failure failure) throws Exception {
File file = screenshotTaker.getScreenshotAs(OutputType.File);
// do something with your file
}
}
Add the listener to your test runner like this...
JUnitCore junit = new JUnitCore();
junit.addListener(new ScreenshotListener((TakesScreenShots) webDriver));
// then run your test...
Result result = junit.run(Request.classes(FullTestSuite.class));

If you want to take a screenshot on test failure, add this class
import java.io.File;
import java.io.IOException;
import java.util.UUID;
import org.apache.commons.io.FileUtils;
import org.junit.rules.MethodRule;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.Statement;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
public class ScreenShotOnFailure implements MethodRule {
private WebDriver driver;
public ScreenShotOnFailure(WebDriver driver){
this.driver = driver;
}
public Statement apply(final Statement statement, final FrameworkMethod frameworkMethod, final Object o) {
return new Statement() {
#Override
public void evaluate() throws Throwable {
try {
statement.evaluate();
} catch (Throwable t) {
captureScreenShot(frameworkMethod.getName());
throw t;
}
}
public void captureScreenShot(String fileName) throws IOException {
File scrFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
fileName += UUID.randomUUID().toString();
File targetFile = new File("./Screenshots/" + fileName + ".png");
FileUtils.copyFile(scrFile, targetFile);
}
};
}
}
And Before all tests, you should use this Rule:
#Rule
public ScreenShotOnFailure failure = new ScreenShotOnFailure(driver));
#Before
public void before() {
...
}

Related

LeanFT & Selenium custom automation framework - no HTML report generated

I have been trying to make LeanFT html reports work with my Selenium/Junit framework, however so far without any joy.
I have searched the topic multiple times on different forums incl. HP official materials and tried all setup methods that I could find.
An XML runresults file is still generated when using a custom Selenium/LeanFT framework.
I create a LeanFT Testing Project project using JUnit as my framework and Selenium as SDK. I also add relevant Selenium jars.
LeanFT version is 14.0.2816.0.
I am conscious of this issue: https://community.softwaregrp.com/t5/UFT-Practitioners-Forum/HTML-report-not-generated-in-custom-framework-using-LeanFT/td-p/1614027 .
I would be grateful, if someone could explain where I am making a mistake here or if the software version is the problem here. Any help is very much appreciated.
The actual setup contains more abstractions, is generally more complex and runs as a jar file, but I have simplified the code for the purpose of this topic as the outcome of both setups is the same - a runresults.xml and no html:
Test Class:
import com.hp.lft.report.CaptureLevel;
import com.hp.lft.report.ModifiableReportConfiguration;
import com.hp.lft.report.Reporter;
import com.hp.lft.sdk.ModifiableSDKConfiguration;
import com.hp.lft.sdk.SDK;
import com.hp.lft.sdk.web.Browser;
import com.hp.lft.sdk.web.BrowserDescription;
import com.hp.lft.sdk.web.BrowserFactory;
import com.hp.lft.sdk.web.BrowserType;
import core.Selenium;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.*;
import java.io.File;
import java.net.URI;
public class SeleniumTest extends Selenium {
WebDriver driver;
Browser browser;
public SeleniumTest() {
//Change this constructor to private if you supply your own public constructor
}
#BeforeClass
public static void setUpBeforeClass() throws Exception {
instance = new SeleniumTest();
globalSetup(SeleniumTest.class);
}
#AfterClass
public static void tearDownAfterClass() throws Exception {
globalTearDown();
}
#Before
public void setUp() throws Exception {
ModifiableSDKConfiguration sdkConfig = new ModifiableSDKConfiguration();
sdkConfig.setServerAddress(new URI("ws://localhost:5095"));
SDK.init(sdkConfig);
ModifiableReportConfiguration reportConfig = new ModifiableReportConfiguration();
reportConfig.setOverrideExisting(true);
reportConfig.setTargetDirectory("C:\\Users\\user\\IdeaProjects\\LeanFT_Selenium\\RunResults");
reportConfig.setReportFolder("LastRun");
reportConfig.setTitle("Summary");
reportConfig.setDescription("Description");
reportConfig.setSnapshotsLevel(CaptureLevel.All);
Reporter.init(reportConfig);
ChromeOptions options = new ChromeOptions();
options.addExtensions(new File
("C:\\Program Files (x86)\\HP\\Unified Functional Testing\\Installations\\Chrome\\Agent.crx"));
System.setProperty("webdriver.chrome.driver",
"C:\\HP_Reporting\\Webdriver\\chromedriver.exe");
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(ChromeOptions.CAPABILITY, options);
driver = new ChromeDriver(options);
browser = BrowserFactory.attach(new BrowserDescription.Builder()
.type(BrowserType.CHROME).build());
}
#After
public void tearDown() throws Exception {
driver.quit();
browser = null;
Reporter.generateReport();
SDK.cleanup();
}
#Test
public void test() throws Exception {
driver.get("https://www.google.co.uk/");
}
}
Selenium Class:
import com.hp.lft.report.Status;
import com.hp.lft.unittesting.UnitTestBase;
import org.junit.After;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.rules.TestWatcher;
public class Selenium extends UnitTestBase{
protected static Selenium instance;
public static void globalSetup(Class<? extends Selenium> testClass) throws Exception {
if (instance == null)
instance = testClass.newInstance();
instance.classSetup();
}
#Before
public void beforeTest() throws Exception {
testSetup();
}
#After
public void afterTest() throws Exception {
testTearDown();
}
public static void globalTearDown() throws Exception {
instance.classTearDown();
getReporter().generateReport();
}
#ClassRule
public static TestWatcher classWatcher = new TestWatcher() {
#Override
protected void starting(org.junit.runner.Description description) {
className = description.getClassName();
}
};
#Rule
public TestWatcher watcher = new TestWatcher() {
#Override
protected void starting(org.junit.runner.Description description) {
testName = description.getMethodName();
}
#Override
protected void failed(Throwable e, org.junit.runner.Description description) {
setStatus(Status.Failed);
}
#Override
protected void succeeded(org.junit.runner.Description description) {
setStatus(Status.Passed);
}
};
#Override
protected String getTestName() {
return testName;
}
#Override
protected String getClassName() {
return className;
}
protected static String className;
protected String testName;
}
Libraries
TL;DR
The report is only generated in 14.00 by extending UnitTestBase. To have the report generated with a custom automation framework, you must upgrade to at least LeanFT 14.01 (latest one at the time of writting is 14.02 though).
Oh, and just for clarification: this issue has nothing to do with Selenium. You'd have the same behavior in C# LeanFT SDK using NUnit 3, for example.
Details
What is a custom automation framework in this context?
When I say custom automation framework I mean any framework that does the SDK and Reporter initialization and cleanup itself.
LeanFT does all the magic through its engine. To tell a custom framework to connect to the engine, you need perform the following steps:
at the beginning of a test suite:
SDK.init();
Reporter.init(); // This is not for the engine, but for the HTML report generation
at the end of a test suite
Reporter.generateReport();
SDK.cleanup();
When you are using the builtin templates, you'll notice that a UnitTestClassBase class is automatically created, that extends from UnitTestBase and that your LeanFtTest class extends from this UnitTestClassBase.
By doing so you are initializing the SDK and the Reporter in a very specific way, which is the reason why with this initialization the HTML report is generated. If you were to reproduce this specific way in your custom framework, you'll also have the HTML report generated. If you are curious, you can check the contents of the UnitTestBase.class file to see what it does.
You are extending from UnitTestBase. Why is it not working?
As mentioned in my comments, you are actually doing the SDK and Reporter initialization twice, once by extending the UnitTestBase (which, as I described above, does that initialization already) and the second time in your setUp method.
Since you are using LeanFT 14.00, you should let the UnitTestBase do the initialization, cleanup and report generation. This means that your Test Class file should be changed to no longer include the init of the SDK and Reporter, as follows:
import com.hp.lft.report.CaptureLevel;
import com.hp.lft.report.ModifiableReportConfiguration;
import com.hp.lft.report.Reporter;
import com.hp.lft.sdk.ModifiableSDKConfiguration;
import com.hp.lft.sdk.SDK;
import com.hp.lft.sdk.web.Browser;
import com.hp.lft.sdk.web.BrowserDescription;
import com.hp.lft.sdk.web.BrowserFactory;
import com.hp.lft.sdk.web.BrowserType;
import core.Selenium;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.*;
import java.io.File;
import java.net.URI;
public class SeleniumTest extends Selenium {
WebDriver driver;
Browser browser;
public SeleniumTest() {
//Change this constructor to private if you supply your own public constructor
}
#BeforeClass
public static void setUpBeforeClass() throws Exception {
instance = new SeleniumTest();
globalSetup(SeleniumTest.class);
}
#AfterClass
public static void tearDownAfterClass() throws Exception {
globalTearDown();
}
#Before
public void setUp() throws Exception {
/*
This will not work in LeanFT 14.00, so we are commenting it out
ModifiableSDKConfiguration sdkConfig = new ModifiableSDKConfiguration();
sdkConfig.setServerAddress(new URI("ws://localhost:5095"));
SDK.init(sdkConfig);
ModifiableReportConfiguration reportConfig = new ModifiableReportConfiguration();
reportConfig.setOverrideExisting(true);
reportConfig.setTargetDirectory("C:\\Users\\user\\IdeaProjects\\LeanFT_Selenium\\RunResults");
reportConfig.setReportFolder("LastRun");
reportConfig.setTitle("Summary");
reportConfig.setDescription("Description");
reportConfig.setSnapshotsLevel(CaptureLevel.All);
Reporter.init(reportConfig);
*/
ChromeOptions options = new ChromeOptions();
options.addExtensions(new File
("C:\\Program Files (x86)\\HP\\Unified Functional Testing\\Installations\\Chrome\\Agent.crx"));
System.setProperty("webdriver.chrome.driver",
"C:\\HP_Reporting\\Webdriver\\chromedriver.exe");
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(ChromeOptions.CAPABILITY, options);
driver = new ChromeDriver(options);
browser = BrowserFactory.attach(new BrowserDescription.Builder()
.type(BrowserType.CHROME).build());
}
#After
public void tearDown() throws Exception {
driver.quit();
browser = null;
//Reporter.generateReport();
//SDK.cleanup();
}
#Test
public void test() throws Exception {
driver.get("https://www.google.co.uk/");
}
}
But I need to configure the SDK and the Report. How can I achieve that in LeanFT 14.00?
The SDK and the Reporter can be configured in two ways:
At initialization, as you attempted to do through the ModifiableSDKConfiguration and ModifiableReportConfiguration
or
In the test settings file (resources/leanft.properties). You can see plenty details in the official help.
You can manipulate some report settings at runtime as well, through the Reporter API:
Set the report level: Reporter.setReportLevel(ReportLevel.All);
Set the snapshot capture level Reporter.setSnapshotCaptureLevel(CaptureLevel.All);
Even if you initialized the SDK and the Reporter through the base class, you can still add custom report events in the report (these work: Reporter.reportEvent();, Reporter.startReportingContext();, Reporter.startTest();, etc.)

Mocking getResource in static block with PowerMock

How to mock getResourceAsStream in the static block?
I think it is untestable.
I reviewed SO and cannot find the answer. The closes-SO-post-here does not address the issue as the call to getResourceAsAStream in the post is not from a static block.
I tried PowerMock, and run into number of limitations. First if I want to mock SomeProperties.class.getResourceAsStream - the static block will execute, as I will need to refer to the class itself. I can suppress static block to prevent doing so, but this will prevent me from getting the static block to execute at all. The solution would be to postpone the execution of the static block until after someProperties.class.getResourceAsStream is mocked.
I do not think it is possible though.
It seems that this code is purely untestable;
Any other ideas?
Here is the code [and a link to GITHUB]:
package com.sopowermock1;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class SomeProperties {
private static Properties props = new Properties();
static {
InputStream is = SomeProperties.class.getResourceAsStream("/some.properties");
try {
props.load(is);
System.out.println("Properties.props.keySet() = " + props.keySet());
} catch (IOException e) {
// How test this branch???
System.out.println("Yes. We got here.");
throw new RuntimeException(e);
}
}
private SomeProperties() {}; // to makes life even harder...
public static String getVersion() {
return props.getProperty("version");
}
}
And here is the test GITHUB Link
package com.sopowermock1;
import java.io.InputStream;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import com.sopowermock1.SomeProperties;
#RunWith(PowerMockRunner.class)
#PrepareForTest(SomeProperties.class)
// This will prevent running static block completely:
// #SuppressStaticInitializationFor("com.sopowermock1.SomeProperties")
public class SomePropertiesTest {
#Mock
private static InputStream streamMock;
#Before
public void setUp() {
MockitoAnnotations.initMocks(SomeProperties.class);
System.out.println("test setUp");
}
#Test(expected = RuntimeException.class)
public void testStaticBlock() {
PowerMockito.mockStatic(SomeProperties.class); // this will mock all static methods (unwanted as we want to call getVersion)
// This will cause static block to be called.
PowerMockito.when(SomeProperties.class.getResourceAsStream("/some.properties")).thenReturn(streamMock);
SomeProperties.getVersion();
}
}
Any ideas?. Full GITHUB source is here.
as mention in How to mock getResourceAsStream method using PowerMockito and JUnit?, use Extract Delegate , then mock the delegate class such as XXStreamFetcher, and then you can test it.

Junit not launching test case when it is an anonymous class

I'm trying to use JUnit for my functional testing. Basically I'm doing this to have access to the JUnit reports. Unfortunately I am running into a problem when trying to launch JUnit from a main method.
Basically I am developing a functional testing tool where the user can provide a test filename as a parameter from the command line. I've simplified it a bit below:
import org.junit.runner.JUnitCore;
public class MainClass {
public static void main(String[] args) throws Exception {
TestCase testCase = new TestCase() {
#Override
public String getPath() {
return args[0];
}
};
JUnitCore junit = new JUnitCore();
junit.run(testCase.getClass());
}
}
The TestCase class then acts on the supplied parameter and provides output:
import org.junit.Assert;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TestCase {
private static final Logger LOGGER = LoggerFactory.getLogger(TestCase.class);
public String getPath() {
return "etc/Default.flow";
}
#Test
public void testFunc() {
try {
LOGGER.info("Entered testFunc()");
Launcher launcher = new Launcher(getPath());
launcher.launch();
launcher.awaitCompletion();
Assert.assertTrue(launcher.getStatus());
LOGGER.info("Success");
} catch (AssertionError e) {
LOGGER.error("Assertion error", e);
}
}
So from the above, we see that the Launcher instance will be launched with a different filename depending on what was entered on the command line.
The problem is however that Junit is not running my anonymous class. Basically the main method exits without any of the assertions or logging taking place. The TestCase testFunc() method is therefore not called at all.
However, when I change the TestCase instance to not be anonymous, everthing works as expected and the testcase is successful:
import org.junit.runner.JUnitCore;
public class MainClass {
public static void main(String[] args) throws Exception {
TestCase testCase = new TestCase();
JUnitCore junit = new JUnitCore();
junit.run(testCase.getClass());
}
}
Why would JUnit launch the Test class only when it is not anonymous?
If you add listener junit.addListener(new TextListener(System.out)); before running test you will see something like:
There were 2 failures:
1) initializationError(junit.MainClass$1)
java.lang.Exception: The class junit.MainClass$1 is not public.
...
2) initializationError(junit.MainClass$1)
java.lang.Exception: Test class should have exactly one public constructor
at org.junit.runners.BlockJUnit4ClassRunner.validateOnlyOneConstructor(BlockJUnit4ClassRunner.java:158)
at org.junit.runners.BlockJUnit4ClassRunner.validateConstructor(BlockJUnit4ClassRunner.java:147)
at org.junit.runners.BlockJUnit4ClassRunner.collectInitializationErrors(BlockJUnit4ClassRunner.java:127)
at org.junit.runners.ParentRunner.validate(ParentRunner.java:416)
at org.junit.runners.ParentRunner.<init>(ParentRunner.java:84)
at org.junit.runners.BlockJUnit4ClassRunner.<init>(BlockJUnit4ClassRunner.java:65)
It means that JUnit is unable to execute test cases represented by anonymous classes.

How to run PowerMock on dynamically created TestCase

I was trying to mock my test suites. My test framework creates test cases by scanning test files on disk. So each time the test cases are dynamically created.
I was trying to use PowerMock. Below is the thing I tried first.
public class GroupTestcase_T extends TestSuite {
static void run() {
scan();
junit.textui.TestRunner.run(g);
}
static void scan() {
// scan disk
for (MyTestCase t : tests) { addTest(t); }
}
}
#RunWith(PowerMockRunner.class)
#PrepareForTest(ClassToStub.class)
public class MyTestCase extends TestCase {
public MyTestCase(TestInfo info) {...}
#Override
protected void setUp() throws Exception {
PowerMockito.mockStatic(ClassToStub.class);
when(ClassToStub.methodToStub())
.thenReturn(new FakeProxy());
}
#Test
public void test() throws Exception {
// Test!
}
}
Above code seems not working:
Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods.
Those methods cannot be stubbed/verified.
2. inside when() you don't call method on mock but on some other object.
3. the parent of the mocked class is not public.
It is a limitation of the mock engine.
I traced the code and found that PowerMockRunner are not called at all.
Also I tried manually force Junit to run it with PowerMockRunner:
Result result = junit.run(new PowerMockRunner(MyTestCase.class));
PowerMockRunner has only one constructor that takes the test class as parameter. My test cases are different each time but all share the same class.
Any idea how to use PowerMock if TestCase are dynamically created?
I was using Junit 4 / PowerMock 1.5
You can generate your tests with the parameterized tests feature and apply the #PowerMockRule.
import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import java.util.Collection;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.rule.PowerMockRule;
#RunWith(Parameterized.class)
#PrepareForTest(ClassToStub.class)
public class MyTestCase{
#Parameters
public static Collection<Object[]> scan() {
return Arrays.asList(new Object[][] {
{ new TestInfo() }, { new TestInfo() } });
}
#Rule
public PowerMockRule rule = new PowerMockRule();
public MyTestCase(TestInfo info) {
// ...
}
#Test
public void test() throws Exception {
PowerMockito.mockStatic(ClassToStub.class);
PowerMockito.when(ClassToStub.methodToStub()).thenReturn(new FakeProxy());
assertTrue(ClassToStub.methodToStub() instanceof FakeProxy);
}
}
Beware, in your example, you are mixing junit 3 (extends TestSuite, protected setUp) and junit 4 (#Test) test definitions.

Powermock : Mocked method still called

First of all, please know that I've searched SO before asking this question, but I was unable to find a satisfying answer.
I'm using JUnit4 and Powermock 1.5.5 (with mockito 1.9.5)
My problem is the following : in my unit tests, I need to mock a static method in a class I can't modify. I only want to mock one method, and not the whole class, so I went for a spy.
Here's what I have so far :
[...]
import static org.mockito.Matchers.*;
import static org.powermock.api.mockito.PowerMockito.*;
#RunWith(JUnitParamsRunner.class)
#ContextConfiguration(locations={"classpath:applicationContext-test.xml"},
loader=MockWebApplicationContextLoader.class)
#MockWebApplication(name="my-app")
#PrepareForTest(value = {
Role.class
})
public class MyTest {
#Rule
public PowerMockRule powerMockRule = new PowerMockRule();
#Before
public void setUp() throws Exception {
initSpring();
mockRoleServices();
}
private void mockRoleServices() throws Exception {
spy(Role.class);
RoleAnswer roleAnswer = new RoleAnswer(RoleEnum.ADMIN);
when(Role.hasAdministratorRole(anyLong(), anyLong(), anyLong()))
.then(roleAnswer);
}
private class RoleAnswer implements Answer<Boolean> {
private RoleEnum roleEnum;
private RoleAnswer(RoleEnum roleEnum) {
this.roleEnum = roleEnum;
}
#Override
public Boolean answer(InvocationOnMock invocation) throws Throwable {
return getRenderRequest().getUserRole() != null &&
getRenderRequest().getUserRole().equals(roleEnum);
}
}
}
Here's the problem : the method Role.hasAdministratorRole() is called instead of being mocked
Here's what I tried so far :
Using mockStatic(Role.class) instead of the spy() method. As expected, all methods are mocked, so I end up getting an NPE before Role.hasAdministratorRole() is called
Doing something like doAnswer(...).when(...). I get a runtime error with powermock telling me my mock is not complete (which actually confirms that something's wrong either with my code or with the lib itself)
Trying to declare the method by its name rather than calling it directly : when(Role.class, "hasAdministratorRole", long.class, long.class, long.class). Same behavior
A bunch of other things I don't recall anymore.
Your help will be greatly appreciated.
Thanks !
EDIT : Thanks to SrikanthLingala's answer, I was able to pinpoint the problem.
This didn't work :
when(Role.hasAdministratorRole(anyLong(), anyLong(), anyLong()))
.thenAnswer(roleAnswer);
but this did :
doAnswer(roleAnswer).when(Role.class, "hasSiteAdministratorRole",
anyLong(), anyLong(), anyLong());
So switching then when() and the answer() worked
As I do not have all of your implementations, I setup some dummy implementations and made a similar setup like yours. The below code works fine for me.
import static junit.framework.Assert.assertTrue;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest(value = {
Role.class
})
public class RoleTest {
#Test
public void mockRoleServices() throws Exception {
PowerMockito.spy(Role.class);
PowerMockito.doAnswer(new RoleAnswer(RoleEnum.ADMIN)).when(Role.class, "hasAdministratorRole", Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong());
Role.printOut();
assertTrue(Role.hasAdministratorRole(1, 1, 1));
}
private class RoleAnswer implements Answer<Boolean> {
private RoleEnum roleEnum;
private RoleAnswer(RoleEnum roleEnum) {
this.roleEnum = roleEnum;
}
public Boolean answer(InvocationOnMock invocation) throws Throwable {
return true;
}
}
}
Dummy Role class:
public class Role {
public static Boolean hasAdministratorRole(long a, long b, long c) {
System.out.println("Inside hasAdministratorRole");
return a + b + c < 0;
}
public static void printOut() {
System.out.println("Inside Printout");
}
}
My test case does not printout Inside hasAdministratorRole, but prints out Inside Printout
Hope this helps
Glad you have solved your issue, this just a warning for everyone else having a similar issue.
Project setup:
Powermock 1.5.5
Mockito 1.9.5
TestNG 6.8.8
Powermock is not taking into account mocks/spies created in a method annotated with #BeforeTest
E.g.:
#BeforeTest
public void setup(){
testee = mock(AClass.class);
}
It gets discarded and then it is entering the mocked method instead of returning the expected result OR throwing all kinds of strange exceptions. When moved to a common test method, it suddenly starts working:
#Test
public void test(){
AClass testee = mock(AClass.class);
....
}
Possibly it is a bug.

Categories