This question already has answers here:
How to verify static void method has been called with power mockito
(2 answers)
Closed 3 years ago.
I have a class A which has a static method testA(String auditUser, Timestamp timestamp) which calls a static method of class B if auditUser is admin.
I am trying to write test for class A.
How can I verify the static method of B got called or not?
class A {
public void static testA(String auditUser, Timestamp timestamp) {
if ("admin".equalsIgnoreCase(auditUser) {
B.testB(timestamp);
}
}
}
class B {
public void static testB(Timestamp timestamp) {
//...some logic...//
}
}
I add void to your static method for compile.
#SpringBootTest
#RunWith(PowerMockTestRunner.class)
#PrepareForTest(value = B.class)
public class TestClass {
#Test
public void testBAdmin() {
String auditUser = "admin";
Timestamp timestamp = new Timestamp(1577447182l);
PowerMockito.mockStatic(B.class);
//You can mock method here, if you need return value like this
//when(B.testB(timestamp)).thenReturn("some_value");
A.testA(auditUser, timestamp);
PowerMockito.verifyStatic(B.class);
B.testB(timestamp);
}
#Test
public void testBNotAdmin() {
String auditUser = "not_admin";
Timestamp timestamp = new Timestamp(1577447182l);
PowerMockito.mockStatic(B.class);
//You can mock method here, if you need return value like this
//when(B.testB(timestamp)).thenReturn("some_value");
A.testA(auditUser, timestamp);
PowerMockito.verifyZeroInteractions(B.class);
}
}
class A {
public static void testA(String auditUser, Timestamp timestamp) {
if ("admin".equalsIgnoreCase(auditUser)) {
B.testB(timestamp);
}
}
}
class B {
public static void testB(Timestamp timestamp) {
//...some logic...//
}
}
And don't forget about maven dependency
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<version>2.0.0-beta.5</version>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>2.0.0-beta.5</version>
</dependency>
Please follow these steps:
Add #PrepareForTest({ClassA.class, ClassB.class})
These use PowerMockito.mockStatic(ClassA.class);, PowerMockito.mockStatic(ClassB.class);
The use PowerMockito.when(ClassA.testA(ArgumentMatchers.anyString(), ArgumentMatchers.any())).thenReturn(PowerMockito.when(ClassB.testB(ArgumentMatchers.any()))).thenReturn(any());
Related
I have two-page objects called OrderSelection and OrderDetails. In addition, I have SharedState class and OrderSelectionStepDef and OrderDetailsStepDef. I declared two variables for OrderSelection and OrderDetails in SharedState. However, they are not initialized in the constructor of SharedState.
In OrderSelectionStepDef and OrderDetailsStepDef classes, I declared their constructors and pass SharedState object.
public OrderSelectionStepDef(SharedState sharedState) {
this.sharedState = sharedState;
}
public OrderDetailsStepDef(SharedState sharedState) {
this.sharedState = sharedState;
}
When I call sharedState.orderDetails within OrderDetailsStepDef or OrderSelectionStepDef a NullPointerException was thrown.
Then, I initialized OrderSelection and OrderDetails class objects in SharedState constructor. Then the issue was solved. But is this implementation ok with cucumber pico container concept?.
Step 1. OrderSelectionStepDef & OrderDetailsStepDef would look like below (please change name as per your implementation)
/**
* Step Definition implementation class for Cucumber Steps defined in Feature file
*/
public class HomePageSteps extends BaseSteps {
TestContext testContext;
public HomePageSteps(TestContext context) {
testContext = context;
}
#When("^User is on Brand Home Page (.+)$")
public void user_is_on_Brand_Home_Page(String siteName) throws InterruptedException {
homePage = new HomePage().launchBrandSite(siteName);
testContext.scenarioContext.setContext(Context.HOMEPAGE, homePage);
}
#Then("^Clicking on Sign In link shall take user to Sign In Page$")
public void clicking_on_Sign_In_link_shall_take_user_to_Sign_In_Page() {
homePage = (HomePage) testContext.scenarioContext.getContext(Context.HOMEPAGE);
signInPage = homePage.ecommSignInPageNavigation();
testContext.scenarioContext.setContext(Context.SIGNINPAGE, signInPage);
}
For your reference
public class BaseSteps {
protected HomePage homePage;
protected PLPPage plpPage;
protected PDPPage pdpPage;
protected ShoppingBagPage shoppingBagPage;
protected ShippingPage shippingPage;
More implementation goes here.....
}
Step 2. Please add below 2 Classes under your framework -
First, Java file name - ScenarioContext.java
public class ScenarioContext {
private Map<String, Object> scenarioContext;
public ScenarioContext(){
scenarioContext = new HashMap<String, Object>();
}
public void setContext(Context key, Object value) {
scenarioContext.put(key.toString(), value);
}
public Object getContext(Context key){
return scenarioContext.get(key.toString());
}
public Boolean isContains(Context key){
return scenarioContext.containsKey(key.toString());
}
}
Second, Java file name - TestContext.java
public class TestContext {
public ScenarioContext scenarioContext;
public TestContext(){
scenarioContext = new ScenarioContext();
}
public ScenarioContext getScenarioContext() {
return scenarioContext;
}
}
Step 3. POM Dependency - picocontainer shall be as per your cucumber version
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-picocontainer</artifactId>
<version>${cucumber.version}</version>
</dependency>
Hope this helps.
I am leaning CDI Annotation have a question with respect to Produces Annotation:
I have a Bank
public interface Bank {
public void withdrawal();
public void deposit();
}
Two Implementation flavors
public class BankOfAmerica implements Bank {
public void withdrawal() {
System.out.println("You are withdrawing from Bank Of America");
}
public void deposit() {
System.out.println("You are depositing in Bank Of America");
}
}
public class Chase implements Bank {
public void withdrawal() {
System.out.println("You are withdrawing from Chase");
}
public void deposit() {
System.out.println("You are depositing in Chase");
}
}
A Qualifier
#Qualifier
#Retention(RUNTIME)
#Target({TYPE, METHOD, PARAMETER, FIELD})
public #interface BankProducer {
}
An Enum
public enum BankName {
DCU(DCU.class), Chase(Chase.class), BankOfAmerica(BankOfAmerica.class);
private Class<? extends Bank> bankType;
private BankName(Class<? extends Bank> bankType) {
this.bankType = bankType;
}
public Class<? extends Bank> getBankType() {
return bankType;
}
}
An Annotation to bind the BankName
#Retention(RUNTIME)
#Target({TYPE, METHOD, PARAMETER, FIELD})
public #interface BankType {
#Nonbinding
BankName value();
}
A Factory
public class BankFactory {
#Produces
#BankProducer
public Bank createBank(#Any Instance<Bank> instance, InjectionPoint injectionPoint) {
Annotated annotated = injectionPoint.getAnnotated();
BankType bankTypeAnnotation = annotated.getAnnotation(BankType.class);
Class<? extends Bank> bankType = bankTypeAnnotation.value().getBankType();
return instance.select(bankType).get();
}
}
And a JUnit
#RunWith(Arquillian.class)
public class ProducesTest {
#Inject
#BankProducer
#BankType(BankName.BankOfAmerica)
private Bank bankOfAmerica;
#Deployment
public static JavaArchive createDeployment() {
return ShrinkWrap.create(JavaArchive.class).addPackages(true, "com.tutorial.produces")
.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml").merge(getDependecies());
}
private static JavaArchive getDependecies() {
JavaArchive[] javaArchives = Maven.configureResolver().loadPomFromFile("pom.xml")
.resolve("org.projectlombok:lombok").withTransitivity().as(JavaArchive.class);
JavaArchive mergedLibraries = ShrinkWrap.create(JavaArchive.class);
for (JavaArchive javaArchive : javaArchives) {
mergedLibraries.merge(javaArchive);
}
return mergedLibraries;
}
#Test
public void create() {
assertEquals(banks.getBankOfAmerica().getClass(), BankOfAmerica.class);
}
}
POM - using tomee
<dependency>
<groupId>org.apache.tomee</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0-1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.tomee</groupId>
<artifactId>arquillian-tomee-embedded</artifactId>
<version>7.0.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.shrinkwrap.resolver</groupId>
<artifactId>shrinkwrap-resolver-depchain</artifactId>
<version>2.2.2</version>
<scope>test</scope>
<type>pom</type>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
I am getting a NullPointer exception in my factory createBank method. InjectionPoint is Null. What is the issue and how do I resolve it?
Alternate Solution: Tried Weld
<dependency>
<groupId>org.jboss.weld.se</groupId>
<artifactId>weld-se</artifactId>
<version>2.2.8.Final</version>
</dependency>
JUnit
#RunWith(WeldJUnit4Runner.class)
public class ProducesWeldTest {
#Inject
#BankProducer
#BankType(BankName.BankOfAmerica)
private Bank bankOfAmerica;
#Test
public void create() {
assertEquals(bankOfAmerica.getClass(), BankOfAmerica.class);
}
}
WeldContext and WeldJUnit4Runner are from here -
http://memorynotfound.com/java-se-unit-testing-cdi-junit-jboss-weld-se/
As I already mentioned in my comment to the post, the CDI implememtatin seems to work. I think the problem lies in the test. Originally, I just wrote a simple test with a main() method and everything works. Now I moved the same code to the JUnit test and it still works. To test your implementation I just added the following client for your factory and a test class as follows:
public class BankClient {
#Inject
#BankProducer
#BankType(BankName.BankOfAmerica)
private Bank bankOfAmerica;
public void deposit() {
bankOfAmerica.deposit();
}
public void withdrawal() {
bankOfAmerica.withdrawal();
}
}
// JUnit test
public class BankServiceTest {
private static Weld weld = new Weld();
private static BankClient sut;
#BeforeClass
public static void initWeld() {
WeldContainer container = weld.initialize();;
sut = container.instance().select(BankClient.class).get();
}
#Test
public void deposit_should_be_invoked() {
sut.deposit();
}
#Test
public void withdrawal_should_be_called() {
sut.withdrawal();
}
#AfterClass
public static void shutDown() {
weld.shutdown();
}
}
After executing the test, you should see the following output on the console and JUnit green bar:
You are depositing in Bank Of America
You are withdrawing from Bank Of America
class StaticClass {
public static String a(){ return "a"; }
public static String ab(){ return a()+"b"; }
}
I want to mock StaticClass::a so that it returns "x" and the call to StaticClass.ab() results in "xb"...
I find it very hard in PowerMock and TestNG...
the exact code I am testing righ now:
class StaticClass {
public static String A() {
System.out.println("Called A");
throw new IllegalStateException("SHOULD BE MOCKED AWAY!");
}
public static String B() {
System.out.println("Called B");
return A() + "B";
}
}
#PrepareForTest({StaticClass.class})
public class StaticClassTest extends PowerMockTestCase {
#Test
public void testAB() throws Exception {
PowerMockito.spy(StaticClass.class);
BDDMockito.given(StaticClass.A()).willReturn("A");
assertEquals("AB", StaticClass.B()); // IllegalStateEx is still thrown :-/
}
}
I have Maven dependencies on:
<artifactId>powermock-module-testng</artifactId>
and
<artifactId>powermock-api-mockito</artifactId>
Why not try something like :
PowerMockito.mockStatic(StaticClass.class);
Mockito.when(StaticClass.a()).thenReturn("x");
Mockito.when(StaticClass.ab()).thenCallRealMethod();
I think this can be accomplished with a Partial Mock.
PowerMock.mockStaticPartial(Mocked.class, "methodToBeMocked");
This might be of help: http://avricot.com/blog/index.php?post/2011/01/25/powermock-%3A-mocking-a-private-static-method-on-a-class
I work on a project with many "BusinessException" that embedded errorCode.
In every unit test for exception, I have to test these error code repeating this kind of pattern:
#Test
public void zipFileReaderCtorShouldThrowAnExceptionWithInexistingArchive() {
try {
zfr = new ZipFileReader("unexpected/path/to/file");
fail("'BusinessZipException' not throwed");
} catch (BusinessZipException e) {
assertThat("Unexpected error code", e.getErrorCode(), is(ErrorCode.FILE_NOT_FOUND));
} catch (Exception e) {
fail("Unexpected Exception: '" + e + "', expected: 'BusinessZipException'");
}
}
(use of JUnit annotation is impossible due to error code testing)
I was bored to do this, particularly because I had to copy/paste exception name in fail()'s error message.
So, I wrote a Util class. I use an abstract class to handle exception assert testing.
public abstract class TestExceptionUtil {
public void runAndExpectException(Class expectedException, String expectedErrorCode) {
String failUnexpectedExceptionMessage = "Unexpected exception. Expected is: '%s', but got: '%s'";
try {
codeToExecute();
fail("'" + expectedException.getName() + "' not throwed");
} catch (BusinessException e) {
if (e.getClass().equals(expectedException)) {
assertThat("Exception error code not expected", e.getErrorCode(), is(expectedErrorCode));
} else {
fail(String.format(failUnexpectedExceptionMessage, expectedException.getName(), e));
}
} catch (Exception e) {
fail(String.format(failUnexpectedExceptionMessage, expectedException.getName(), e));
}
}
abstract public void codeToExecute();
}
Then, client use it in this way :
#Test
public void zipFileReaderCtorShouldThrowAnExceptionWithInexistingArchive() {
new TestExceptionUtil() {
#Override
public void codeToExecute() {
zfr = new ZipFileReader("unexpected/path/to/file");
}
}.runAndExpectException(BusinessTechnicalException.class, ErrorCode.FILE_NOT_FOUND);
}
Do you think it's "clean" ? Do you think it can be ameliorated ? Do you think it's too heavy and/or useless?
My primary objective is to uniformize testing exception in our dev team. (and of course factorize code)
Thanks for reading!
How about the JUnit ExpectedException Rule?
First you declare the Rule at the top of the test class:
#Rule
public final ExpectedException ee = ExpectedException.none();
Then in your test method you can declare that you can expect an Exception:
#Test
public void testStuff() {
ee.expect(IllegalArgumentException.class);
ee.expectMessage("My Exception text");
}
I think this is significatly cleaner than your approach.
You can then use hamcrest Matchers to match the Exception message:
#Test
public void testStuff() {
ee.expect(IllegalArgumentException.class);
ee.expectMessage(containsString("error"));
ee.expect(hasProperty("errorCode", is(7)));
}
The hasProperty Matcher will look for a getter for the named property and check that it matches the second argument - which is another Matcher.
You can even implement your own Matcher, in which case you will not require a dependency on hamcrest:
public class ErrorCodeMatcher extends BaseMatcher<Throwable> {
private final int expectedErrorCode;
public ErrorCodeMatcher(int expectedErrorCode) {
this.expectedErrorCode = expectedErrorCode;
}
#Override
public boolean matches(Object o) {
return ((BusinessZipException) o).getErrorCode() == expectedErrorCode;
}
#Override
public void describeTo(Description d) {
d.appendText("Expected error code was" + expectedErrorCode);
}
}
This would be used as follows:
ee.expect(new ErrorCodeMatcher(7));
With a static factory method and a static import this can become quite clean:
ee.expect(exceptionWithErrorCode(7));
If you have a common interface that defines your business Exception with a getErrorCode() method, say called ErrorAwareException then you can extend the TypeSafeMatcher<T> class to create slightly cleaner code:
public class ErrorCodeMatcher<T extends Exception & ErrorAwareException> extends TypeSafeMatcher<T> {
public static <E extends Exception & ErrorAwareException> ErrorCodeMatcher<E> exceptionWithErrorCode(final int expectedErrorCode) {
return new ErrorCodeMatcher<E>(expectedErrorCode);
}
private final int expectedErrorCode;
public ErrorCodeMatcher(int expectedErrorCode) {
this.expectedErrorCode = expectedErrorCode;
}
#Override
protected boolean matchesSafely(final T t) {
return t.getErrorCode() == expectedErrorCode;
}
#Override
public void describeTo(Description d) {
d.appendText("Expected error code was" + expectedErrorCode);
}
}
Note that if you do choose to use hamcrest then make sure that you include junit-dep rather than pure junit in your project otherwise the hamcrest classes will clash with the hamcrest classes included with junit. In maven, this will look something like this:
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit-dep</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
I think you are actually reinventing the wheel here. You can use either expected parameter of the #Test annotation which causes test method to succeed of given exception was thrown. Or use the ExpectedException rule does basically the same but has more functionality. So try either
#Test(expected = Exception.class)
public void myTest() {
throw new Exception();
}
or
#Rule
private ExpectedException rule = ExpectedException.none();
#Test
public void myTest() {
rule.expect(Exception.class);
throw new Exception();
}
I want to mock the default constructor of java.util.date so it does not construct
a Date object representing the time when it was created, but always the same Date object (in my example below 31 Dec 2010). I tried doing this with JMockit and JUnit, but when executing my test below, the output is always Thu Jan 01 01:00:00 CET 1970. So what is wrong with my mock of Date()?
import java.util.Date;
import org.junit.*;
import mockit.*;
public class AppTest {
#Before
public void setUp() {
Mockit.setUpMocks(MockedDate.class);
}
#After
public void tearDown() {
Mockit.tearDownMocks();
}
#Test
public void testDate() {
Date today=new Date();
System.out.println(today.toString());
}
#MockClass(realClass=Date.class)
public static class MockedDate {
#Mock
public void $init() {
// Now should be always 31.12.2010!
new Date(110,11,31); //110 = 2010! 11 = December! This is sick!
}
}
}
al nik's answer was a good hint for me. It is better to mock the System class instead of the Date class to generate a fake time. My own solution in the end was simply to mock the System.currentTimeMillis() method (this method is called by Date() internally).
JMockit 1.5 and later
new MockUp<System>(){
#Mock
public long currentTimeMillis() {
// Now is always 11/11/2011
Date fake = new Date(111,10,11);
return fake.getTime();
}
};
JMockit 1.4 and earlier
#MockClass(realClass = System.class)
public static class MockedSystem {
#Mock
public long currentTimeMillis() {
// Now is always 11/11/2011
Date fake = new Date(111,10,11);
return fake.getTime();
}
}
As suggested in the Test Driven book it's good practice to use a SystemTime abstraction in your java classes.
Replace your method calls (System#currentTimeMillis and Calendar#getInstance) and direct construction (new Date()) with static method calls like:
long time = SystemTime.asMillis();
Calendar calendar = SystemTime.asCalendar();
Date date = SystemTime.asDate();
To fake the time you just need to modify what's returned by your SystemTime class.
SystemTime use a TimeSource interface that by default delegates to System.currentTimeMillis()
public interface TimeSource {
long millis();
}
a configurable SystemTime implementation could be something like this
public class SystemTime {
private static final TimeSource defaultSrc =
new TimeSource() {
public long millis() {
return System.currentTimeMillis();
}
};
private static TimeSource source = null;
public static long asMillis() {
return getTimeSource().millis();
}
public static Date asDate() {
return new Date(asMillis());
}
public static void reset() {
setTimeSource(null);
}
public static void setTimeSource(TimeSource source) {
SystemTime.source = source;
}
private static TimeSource getTimeSource() {
return (source != null ? source : defaultSrc);
}
}
and to fake the returned time you simply do
#Test
public void clockReturnsFakedTimeInMilliseconds() throws Exception {
final long fakeTime = 123456790L;
SystemTime.setTimeSource(new TimeSource() {
public long millis() {
return fakeTime;
}
});
long clock = SystemTime.asMillis();
assertEquals("Should return fake time", fakeTime, clock);
}
Joda-Time library simplifies working with dates in Java and offers you something like this out of the box
You mocked the constructor, and inside you made an instance of Date (that has nothing to do with the one constructed) and just threw it away. Since the default constructor is mocked out, date is not initialized to the current time, and so you get the time of zero (which represents 1970-01-01).
To modify the returned date you need to use a magic "it" attribute, like so:
#MockClass(realClass=Date.class)
public static class MockedDate {
public Date it;
#Mock
public void $init() {
// This is sick!
it.setDate(31);
it.setYear(110); // 110 = 2010!
it.setMonth(11); // 11 = December!
}
}
And here's a complete JUnit example based on #asmaier's great answer:
#Test
public void dateConstructorReturnsMockedDate() throws ParseException {
final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
final Date mockDate = dateFormat.parse("2002-02-02");
new MockUp<System>(){
#Mock
public long currentTimeMillis() {
return mockDate.getTime();
}
};
final Date actualDate = new Date();
assertThat(actualDate).isEqualTo(mockDate); // using AssertJ
}
When using Maven, configure JMockit as follows in pom.xml:
<dependencies>
<dependency>
<groupId>org.jmockit</groupId>
<artifactId>jmockit</artifactId>
<version>${jmockit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<argLine>
-javaagent:${settings.localRepository}/org/jmockit/jmockit/${jmockit.version}/jmockit-${jmockit.version}.jar
</argLine>
<disableXmlReport>true</disableXmlReport>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<jmockit.version>1.44</jmockit.version>
</properties>