JUnit测试中无法Mock对象,遭遇JVMCFRE074类格式错误
java.lang.ClassFormatError: JVMCFRE074 no Code attribute specified for FacesContext Mocking Hey, let's break down this error and fix it step by step! That JVMCFRE074 error is telling you that the JVM tried to load javax.faces.context.FacesContext, but the class file doesn't have actual method bytecode (the "Code attribute") attached to its methods. Here's why that happens and how to fix it:
Why This Error Occurs
Almost always, this is caused by a dependency mismatch:
- You're only including the JSF API JAR (like
jsf-api) in your test classpath. This JAR only contains class signatures and method declarations—no actual implementation code. When the JVM tries to use this class (even for mocking), it can't find the bytecode it needs to execute. - Or, your JSF implementation JAR (like Mojarra's
jsf-implor MyFaces'myfaces-impl) is marked with aprovidedscope, meaning it's excluded from the test runtime.
Step-by-Step Fixes
1. Fix Your JSF Dependencies
Make sure you have both the JSF API and a full implementation JAR available during test execution. If you're using Maven, adjust your pom.xml like this:
<!-- JSF API for compilation --> <dependency> <groupId>javax.faces</groupId> <artifactId>jsf-api</artifactId> <version>2.2.20</version> <scope>compile</scope> </dependency> <!-- JSF implementation (required for test runtime) --> <dependency> <groupId>com.sun.faces</groupId> <artifactId>jsf-impl</artifactId> <version>2.2.20</version> <scope>test</scope> <!-- Use "compile" if your app needs it at runtime too --> </dependency>
For Gradle users, adjust your build script to include the implementation dependency in the testRuntimeOnly or implementation configuration.
2. Use a Mock Framework Instead of Manual Mocks
FacesContext is an abstract class—don't try to instantiate it directly. Tools like Mockito create dynamic proxy instances that work with just the API JAR, avoiding the need for a full implementation. Here's a quick example:
import javax.faces.context.FacesContext; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; public class YourServiceTest { @Mock private FacesContext mockFacesContext; @BeforeEach void setUp() { MockitoAnnotations.openMocks(this); } @Test void testYourBusinessLogic() { // Configure mock behavior as needed // Example: when(mockFacesContext.getExternalContext()).thenReturn(mockExternalContext); // Run your test logic here } }
This way, you don't rely on the actual JSF implementation code for mocking.
3. Check for Dependency Conflicts
Sometimes conflicting JSF versions or duplicate JARs can cause this issue. Run this command to inspect your dependency tree and spot conflicts:
mvn dependency:tree
If you find multiple JSF API/implementation entries, use <exclusions> in your pom.xml to remove the unwanted ones.
4. Fix Custom Mock Classes (If You're Using Them)
If you wrote a custom FacesContext subclass, make sure you implement all abstract methods—even if they're empty. The JVM requires a Code attribute for every method, so don't leave any abstract method unimplemented:
public class MockFacesContext extends FacesContext { @Override public void release() { // Empty implementation or custom logic } @Override public ExternalContext getExternalContext() { // Return a mock or stub ExternalContext return new MockExternalContext(); } // Implement ALL other abstract methods from FacesContext here }
Final Notes
Start with fixing your dependencies—this is the most common root cause. If that doesn't work, switch to a mock framework like Mockito, which is designed for exactly these kinds of scenarios.
内容的提问来源于stack exchange,提问作者rickcoup

