Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add the support for powermock and junit4 #26

Merged
merged 8 commits into from
Mar 19, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.weirddev.testme.intellij.generator;

import com.weirddev.testme.intellij.configuration.TestMeConfig;
import com.weirddev.testme.intellij.configuration.TestMeConfigPersistent;
import com.weirddev.testme.intellij.template.FileTemplateConfig;
import com.weirddev.testme.intellij.template.TemplateRegistry;
import com.weirddev.testme.intellij.template.context.Language;

public class TestMeGeneratorJunit4PowerMockTest extends TestMeGeneratorTestBase {

public TestMeGeneratorJunit4PowerMockTest() {
super(TemplateRegistry.JUNIT4_POWERMOCK_JAVA_TEMPLATE, "testPowerMock", Language.Java);
}

public void testSimpleClass() {
doTest();
}

public void testVariousFieldTypes() {
final TestMeConfig testMeConfig = new TestMeConfig();
testMeConfig.setOptimizeImports(false);
testMeConfig.setReplaceFullyQualifiedNames(false);
final FileTemplateConfig fileTemplateConfig = new FileTemplateConfig(testMeConfig);
doTest(fileTemplateConfig);
}

public void testMockFieldsInDependencyInjection() {
doTest(new FileTemplateConfig(TestMeConfigPersistent.getInstance().getState()));
}

public void testRenderInternalMethodCallStubs() {
final TestMeConfig testMeConfig = new TestMeConfig();
testMeConfig.setRenderInternalMethodCallStubs(true);
final FileTemplateConfig fileTemplateConfig = new FileTemplateConfig(testMeConfig);
doTest(fileTemplateConfig);
}

public void testRenderInternalMethodCallStubsIgnored() {
doTest(new FileTemplateConfig(TestMeConfigPersistent.getInstance().getState()));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ public class TestMeConfig {
*/
private boolean optimizeImports= true;

/**
* Test generator behavior option. Generate stubs for internal method calls in powermock
* Valid values:true,false
* Default:false
*/
private boolean renderInternalMethodCallStubs = false;

public boolean getGenerateTestsForInheritedMethods() {
return generateTestsForInheritedMethods;
}
Expand Down Expand Up @@ -62,4 +69,12 @@ public boolean getOptimizeImports() {
public void setOptimizeImports(boolean optimizeImports) {
this.optimizeImports = optimizeImports;
}

public boolean isRenderInternalMethodCallStubs() {
return renderInternalMethodCallStubs;
}

public void setRenderInternalMethodCallStubs(boolean renderInternalMethodCallStubs) {
this.renderInternalMethodCallStubs = renderInternalMethodCallStubs;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.intellij.psi.impl.PsiManagerEx;
import com.weirddev.testme.intellij.template.FileTemplateContext;
import com.weirddev.testme.intellij.template.context.MockitoMockBuilder;
import com.weirddev.testme.intellij.template.context.PowerMockBuilder;
import com.weirddev.testme.intellij.template.context.StringUtils;
import com.weirddev.testme.intellij.template.context.TestSubjectInspector;
import org.jetbrains.annotations.NotNull;
Expand All @@ -26,9 +27,24 @@ public MockBuilderFactory() {
}

@NotNull
public MockitoMockBuilder createMockitoMockBuilder(FileTemplateContext context, TestSubjectInspector testSubjectInspector, List<String> classpathJars) {
public MockitoMockBuilder createMockitoMockBuilder(FileTemplateContext context,
TestSubjectInspector testSubjectInspector, List<String> classpathJars) {
return new MockitoMockBuilder(isMockInline(context),
context.getFileTemplateConfig().isStubMockMethodCallsReturnValues(), testSubjectInspector,
resolveMockitoVersion(classpathJars));
}

@NotNull
public PowerMockBuilder createPowerMockBuilder(FileTemplateContext context,
TestSubjectInspector testSubjectInspector, List<String> classpathJars) {
return new PowerMockBuilder(true,
context.getFileTemplateConfig().isStubMockMethodCallsReturnValues(), testSubjectInspector,
resolveMockitoVersion(classpathJars), context.getFileTemplateConfig().isRenderInternalMethodCallStubs());
}

private boolean isMockInline(FileTemplateContext context) {
boolean found = false;
// final VirtualFile mockMakerVFile = ResourceFileUtil.findResourceFileInScope("mockito-extensions/org.mockito.plugins.MockMaker", context.getProject(), context.getTestModule().getModuleWithDependenciesAndLibrariesScope(true));
// final VirtualFile mockMakerVFile = ResourceFileUtil.findResourceFileInScope("mockito-extensions/org.mockito.plugins.MockMaker", context.getProject(), context.getTestModule().getModuleWithDependenciesAndLibrariesScope(true));
final VirtualFile mockMakerVFile = ResourceFileUtil.findResourceFileInDependents(context.getTestModule(), "mockito-extensions/org.mockito.plugins.MockMaker");
logger.debug("found mockito MockMaker in test module classpath:" + mockMakerVFile);
if (mockMakerVFile != null) {
Expand All @@ -40,7 +56,7 @@ public MockitoMockBuilder createMockitoMockBuilder(FileTemplateContext context,
logger.debug("is mock-maker-inline turned on:" + found);
}
}
return new MockitoMockBuilder(found, context.getFileTemplateConfig().isStubMockMethodCallsReturnValues(), testSubjectInspector, resolveMockitoVersion(classpathJars));
return found;
}

@Nullable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ public Map<String, Object> build(FileTemplateContext context, Properties default
ctxtParams.put(TestMeTemplateParams.TestSubjectUtils, testSubjectInspector);
List<String> classpathJars = resolveClasspathJars(context);
ctxtParams.put(TestMeTemplateParams.MockitoMockBuilder, mockBuilderFactory.createMockitoMockBuilder(context, testSubjectInspector, classpathJars));
ctxtParams.put(TestMeTemplateParams.PowerMockBuilder, mockBuilderFactory.createPowerMockBuilder(context, testSubjectInspector, classpathJars));
ctxtParams.put(TestMeTemplateParams.TestedClasspathJars, classpathJars);
logger.debug("Done building Test Template context in "+(new Date().getTime()-start)+" millis");
return ctxtParams;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public class IconRegistry {
static {
add(new IconDescriptor("JUnit4", Icons.JUNIT4, Icons.JUNIT4_DARK));
add(new IconDescriptor("JUnit5", Icons.JUNIT5,Icons.JUNIT5));
add(new IconDescriptor("Powermock", Icons.POWERMOCK,Icons.POWERMOCK));
add(new IconDescriptor("Mockito", Icons.MOCKITO,Icons.MOCKITO));
add(new IconDescriptor("Groovy", Icons.GROOVY,Icons.GROOVY));
add(new IconDescriptor("Scala", Icons.SCALA,Icons.SCALA));
Expand Down
1 change: 1 addition & 0 deletions src/main/java/com/weirddev/testme/intellij/icon/Icons.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public interface Icons {
Icon GROOVY = getIcon("/icons/groovy.png");
Icon SCALA = getIcon("/icons/scala.png");
Icon MOCKITO = getIcon("/icons/mockito.png");
Icon POWERMOCK = getIcon("/icons/powermock.png");
Icon JUNIT4 = getIcon("/icons/junit.png");
Icon JUNIT5 = getIcon("/icons/junit5.png");
Icon JUNIT4_DARK = getIcon("/icons/junit_dark.png");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public enum TemplateIcons {
JUnit4( IconFiles.JUNIT4, IconFiles.JUNIT4_DARK),
JUnit5( IconFiles.JUNIT5, IconFiles.JUNIT5),
Mockito( IconFiles.MOCKITO, IconFiles.MOCKITO),
Powermock( IconFiles.POWERMOCK, IconFiles.POWERMOCK),
Groovy( IconFiles.GROOVY, IconFiles.GROOVY),
Scala( IconFiles.SCALA, IconFiles.SCALA),
TestNG( IconFiles.TESTNG, IconFiles.TESTNG),
Expand All @@ -26,6 +27,7 @@ private static class IconFiles {
private static final String JUNIT5 = "/icons/junit5.png";
private static final String JUNIT4_DARK = "/icons/junit_dark.png";
private static final String TESTNG = "/icons/testNG.png";
private static final String POWERMOCK = "/icons/powermock.png";
}

private final Icon icon;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,21 @@ public class FileTemplateConfig {
*/
private boolean generateTestsForInheritedMethods = true;

/**
* Test generator behavior option. Generate stubs for internal method calls in powermock
* Valid values:true,false
* Default:true
*/
private boolean renderInternalMethodCallStubs = false;

public FileTemplateConfig(TestMeConfig testMeConfig) {
this(
Integer.valueOf(System.getProperties().getProperty("testMe.generator.maxRecursionDepth", FileTemplateConfig.DEFAULT_MAX_RECURSION_DEPTH + "")),
testMeConfig == null || testMeConfig.getReformatCode(),
testMeConfig == null || testMeConfig.getReplaceFullyQualifiedNames(),
testMeConfig == null || testMeConfig.getOptimizeImports(),
testMeConfig == null || testMeConfig.getGenerateTestsForInheritedMethods(),
testMeConfig == null || testMeConfig.isRenderInternalMethodCallStubs(),
Boolean.valueOf(System.getProperties().getProperty("testMe.generator.ignoreUnusedProperties", "true")),
Boolean.valueOf(System.getProperties().getProperty("testMe.generator.replaceInterfaceParamsWithConcreteTypes", "true")),
Boolean.valueOf(System.getProperties().getProperty("testMe.generator.stubMockMethodCallsReturnValues", "true")),
Expand All @@ -100,13 +108,14 @@ public FileTemplateConfig(TestMeConfig testMeConfig) {

}

private FileTemplateConfig(int maxRecursionDepth, boolean reformatCode, boolean replaceFqn, boolean optimizeImports, boolean generateTestsForInheritedMethods, boolean ignoreUnusedProperties, boolean replaceInterfaceParamsWithConcreteTypes, boolean stubMockMethodCallsReturnValues,
private FileTemplateConfig(int maxRecursionDepth, boolean reformatCode, boolean replaceFqn, boolean optimizeImports, boolean generateTestsForInheritedMethods, boolean renderInternalMethodCallStubs, boolean ignoreUnusedProperties, boolean replaceInterfaceParamsWithConcreteTypes, boolean stubMockMethodCallsReturnValues,
int maxNumOfConcreteCandidatesToReplaceInterfaceParam, int minPercentOfExcessiveSettersToPreferMapCtor, int minPercentOfInteractionWithPropertiesToTriggerConstructorOptimization) {
this.maxRecursionDepth = maxRecursionDepth;
this.reformatCode = reformatCode;
this.replaceFqn = replaceFqn;
this.optimizeImports = optimizeImports;
this.generateTestsForInheritedMethods = generateTestsForInheritedMethods;
this.renderInternalMethodCallStubs = renderInternalMethodCallStubs;
this.stubMockMethodCallsReturnValues = stubMockMethodCallsReturnValues;
this.ignoreUnusedProperties = ignoreUnusedProperties;
this.replaceInterfaceParamsWithConcreteTypes = replaceInterfaceParamsWithConcreteTypes;
Expand Down Expand Up @@ -186,4 +195,12 @@ public void setMaxNumOfConcreteCandidatesToReplaceInterfaceParam(int maxNumOfCon
public boolean isGenerateTestsForInheritedMethods() {
return generateTestsForInheritedMethods;
}

public boolean isRenderInternalMethodCallStubs() {
return renderInternalMethodCallStubs;
}

public void setRenderInternalMethodCallStubs(boolean renderInternalMethodCallStubs) {
this.renderInternalMethodCallStubs = renderInternalMethodCallStubs;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public class TemplateRegistry {
static private List<TemplateDescriptor> templateDescriptors = new ArrayList<TemplateDescriptor>();

public static final String JUNIT4_MOCKITO_JAVA_TEMPLATE = "JUnit4 & Mockito.java";
public static final String JUNIT4_POWERMOCK_JAVA_TEMPLATE = "JUnit4 & Powermock.java";
public static final String JUNIT5_MOCKITO_JAVA_TEMPLATE = "JUnit5 & Mockito.java";
public static final String TESTNG_MOCKITO_JAVA_TEMPLATE = "TestNG & Mockito.java";
public static final String JUNIT4_MOCKITO_GROOVY_TEMPLATE = "Groovy, JUnit4 & Mockito.groovy";
Expand All @@ -39,6 +40,9 @@ public class TemplateRegistry {
templateDescriptors.add(new TemplateDescriptor("<html><i>JUnit4</i>"+ TemplateIcons.JUnit4.asHtml()+"& <i>Mockito</i>" + TemplateIcons.Mockito.asHtml()+ "</html>",
"<html><i>JUnit4</i></html><JUnit4><html>& <i>Mockito</i></html><Mockito>",
JUNIT4_MOCKITO_JAVA_TEMPLATE, Language.Java, TemplateRole.Tester));
templateDescriptors.add(new TemplateDescriptor("<html><i>JUnit4</i>"+ TemplateIcons.JUnit4.asHtml()+"& <i>Powermock</i>" + TemplateIcons.Powermock.asHtml()+ "</html>",
"<html><i>JUnit4</i></html><JUnit4><html>& <i>Powermock</i></html><Powermock>",
JUNIT4_POWERMOCK_JAVA_TEMPLATE, Language.Java, TemplateRole.Tester));
templateDescriptors.add(new TemplateDescriptor("<html><i>JUnit5</i>"+ TemplateIcons.JUnit5.asHtml()+"& <i>Mockito</i>" + TemplateIcons.Mockito.asHtml()+ "</html>",
"<html><i>JUnit5</i></html><JUnit5><html>& <i>Mockito</i></html><Mockito>",
JUNIT5_MOCKITO_JAVA_TEMPLATE, Language.Java, TemplateRole.Tester));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,4 +144,12 @@ public boolean hasReturn(){
return returnType != null && !"void".equals(returnType.getName());
}

/**
*
* true - if method has parameters
*/
public boolean hasParams() {
return !methodParams.isEmpty();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public class MockitoMockBuilder {
*/
private final boolean isMockitoMockMakerInlineOn;
private final boolean stubMockMethodCallsReturnValues;
private final TestSubjectInspector testSubjectInspector;
protected final TestSubjectInspector testSubjectInspector;
@Nullable
private final String mockitoCoreVersion;
private final Integer mockitoCoreMajorVersion;
Expand Down Expand Up @@ -120,26 +120,12 @@ public boolean isMockable(Field field) {
public boolean isMockable(Field field, Type testedClass) {
final boolean isMockable = !field.getType().isPrimitive() && !isWrapperType(field.getType())
&& (!field.getType().isFinal() || isMockitoMockMakerInlineOn) && !field.isOverridden()
&& !field.getType().isArray() && !field.getType().isEnum() && !isNotInjectedInDiClass(field, testedClass);
&& !field.getType().isArray() && !field.getType().isEnum()
&& !testSubjectInspector.isNotInjectedInDiClass(field, testedClass);
LOG.debug("field " + field.getType().getCanonicalName() + " " + field.getName() + " is mockable:" + isMockable);
return isMockable;
}

/**
* Avoid mocking a field if all these conditions are met:
* class has DI annotation
* field has no direct DI annotation
* field does not have a setter
* there is no class constructor.
* @param field field
* @param testedClass testedClass
* @return true if field meet conditions above
*/
private boolean isNotInjectedInDiClass(Field field, Type testedClass) {
return testedClass != null && testedClass.isAnnotatedByDI() && !field.isAnnotatedByDI() && !field.isHasSetter()
&& !testedClass.hasConstructor();
}

/**
* true - if argument can be mocked given the provided default types
*/
Expand All @@ -164,24 +150,13 @@ public boolean hasMockable(List<Field> fields, Type testedClass) {
return false;
}

/**
* for class with only private constructor that can not mock, for example util classes only with static methods
* @param testedClass tested class
* @return true - if tested class has public constructors
*/
private boolean hasAccessibleCtor(Type testedClass) {
// filter the constructors
List<Method> constructorList = testedClass.findConstructors();
return constructorList.isEmpty() || constructorList.stream().anyMatch(method -> !method.isPrivate());
}

/**
*
* @param testedClass the tested class
* @return true - if the tested class has mockable field
*/
public boolean hasMocks(Type testedClass) {
return hasAccessibleCtor(testedClass) && hasMockable(testedClass.getFields(), testedClass);
return testSubjectInspector.hasAccessibleCtor(testedClass) && hasMockable(testedClass.getFields(), testedClass);
}

/**
Expand Down Expand Up @@ -271,6 +246,7 @@ public boolean shouldStub(Method testMethod, List<Field> testedClassFields) {
return callsMockMethod(testMethod, testedClassFields, Method::hasReturn, null);
}


/**
* true - if should stub tested method
* @param testMethod method being tested
Expand Down Expand Up @@ -386,7 +362,7 @@ public boolean isMockExpected(Field field) {
/**
* true - if type is a wrapper for other type, such as a primitive
*/
private boolean isWrapperType(Type type) {
protected boolean isWrapperType(Type type) {
return WRAPPER_TYPES.contains(type.getCanonicalName());
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.weirddev.testme.intellij.template.context;

import com.intellij.openapi.diagnostic.Logger;
import org.jetbrains.annotations.Nullable;

public class PowerMockBuilder extends MockitoMockBuilder{

private static final Logger LOG = Logger.getInstance(PowerMockBuilder.class.getName());

/**
* true when render internal method call option is opted-in on custom settings
*/
private final boolean renderInternalMethodCallStubs;

public PowerMockBuilder(boolean isMockitoMockMakerInlineOn, boolean stubMockMethodCallsReturnValues,
huangliang992 marked this conversation as resolved.
Show resolved Hide resolved
TestSubjectInspector testSubjectInspector, @Nullable String mockitoCoreVersion,
boolean renderInternalMethodCallStubs) {
super(isMockitoMockMakerInlineOn, stubMockMethodCallsReturnValues, testSubjectInspector, mockitoCoreVersion);
this.renderInternalMethodCallStubs = renderInternalMethodCallStubs;
}

/**
*
* @param method tested method
* @param testedClass tested class
* @return true if method has class internal method call
*/
public boolean hasInternalMethodCall(Method method, Type testedClass) {
return renderInternalMethodCallStubs && method.getMethodCalls().stream().anyMatch(methodCall -> testedClass.getMethods().stream()
.anyMatch(classMethod -> classMethod.getMethodId().equals(methodCall.getMethod().getMethodId())));
}

/**
* true - field can be mocked
*/
@Override
public boolean isMockable(Field field, Type testedClass) {
final boolean isMockable = !field.getType().isPrimitive() && !isWrapperType(field.getType())
&& !field.isOverridden() && !field.getType().isArray() && !field.getType().isEnum()
&& !testSubjectInspector.isNotInjectedInDiClass(field, testedClass);
LOG.debug("field " + field.getType().getCanonicalName() + " " + field.getName() + " is mockable:" + isMockable);
return isMockable;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ public interface TestMeTemplateParams {
* @see MockitoMockBuilder
*/
String MockitoMockBuilder = "MockitoMockBuilder";
/**
* instance of {@link com.weirddev.testme.intellij.template.context.PowerMockBuilder}
* @see PowerMockBuilder
*/
String PowerMockBuilder = "PowerMockBuilder";
/**
* instance of {@link com.weirddev.testme.intellij.template.context.TestSubjectInspector}
* @see TestSubjectInspector
Expand Down
Loading
Loading