如何Mock JGit的git.push()命令?JUnit测试遇异常求助
Absolutely, you can mock or bypass the actual remote push operation to run your tests locally without hitting a real remote repository. Here are a few practical approaches tailored to your scenario:
1. Mock the PushCommand Directly with a Mocking Framework (e.g., Mockito)
If you want to completely skip any real Git operations for the push step, use a mocking library to fake the PushCommand behavior. This is perfect for pure unit tests where you just need to verify the push method is called correctly, without executing actual repository logic.
import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.PushCommand; import org.eclipse.jgit.transport.PushResult; import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; import org.mockito.Mockito; // Mock core JGit objects Git mockGit = Mockito.mock(Git.class); PushCommand mockPushCommand = Mockito.mock(PushCommand.class); // Stub the fluent method chain to return the mock command Mockito.when(mockGit.push()).thenReturn(mockPushCommand); Mockito.when(mockPushCommand.setCredentialsProvider(Mockito.any(UsernamePasswordCredentialsProvider.class))) .thenReturn(mockPushCommand); // Make the call() method return a fake success result instead of throwing an exception Mockito.when(mockPushCommand.call()).thenReturn(new PushResult()); // Use this mockGit instance in your test code instead of a real Git object // Your code under test will interact with the mock, and no real push will occur
2. Use a Local Bare Repository as a "Mock Remote"
If you want to test the full push workflow without network calls, create a local bare repository to act as your fake remote. This mimics real push behavior but stays entirely on your local machine, making it great for integration-style tests.
import org.eclipse.jgit.api.Git; import org.eclipse.jgit.transport.URIish; import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; import java.io.File; import java.nio.file.Files; // Create a temporary local bare repository (acts as your mock remote) File remoteRepoDir = Files.createTempDirectory("mock-remote-repo").toFile(); Git.init().setDirectory(remoteRepoDir).setBare(true).call(); // Configure your existing local repo to point to this mock remote Git localGit = Git.open(yourLocalRepoDir); localGit.remoteAdd() .setName("origin") .setUri(new URIish(remoteRepoDir.getAbsolutePath())) .call(); // Now execute the push command - it will push to the local bare repo, no network required localGit.push() .setCredentialsProvider(new UsernamePasswordCredentialsProvider(PortalConstants.USERNAME, PortalConstants.PASSWORD)) .call(); // Clean up temporary resources after the test localGit.close(); // Add logic to delete remoteRepoDir if needed
3. Customize JGit's Transport to Skip Push Logic
For deeper control, you can override JGit's Transport class to skip the actual push operation. This is useful if you need to intercept push requests across your entire test suite.
import org.eclipse.jgit.transport.*; import java.io.IOException; import java.util.Collection; // Custom Transport that fakes a successful push without doing any work public class MockTransport extends Transport { protected MockTransport(Repository local, URIish uri) { super(local, uri); } @Override public void push(ProgressMonitor monitor, Collection<RemoteRefUpdate> refUpdates) throws IOException { // Mark all reference updates as successful for (RemoteRefUpdate update : refUpdates) { update.setStatus(RemoteRefUpdate.Status.OK); } } // Implement required abstract methods with no-op or fake behavior @Override public FetchConnection openFetch() throws IOException { return null; } @Override public PushConnection openPush() throws IOException { return null; } @Override public void close() {} } // Register the mock transport in your test setup Transport.registerTransport("file", new TransportFactory() { @Override public Transport create(Repository local, URIish uri) { return new MockTransport(local, uri); } }); // Now when you call git.push().call(), it will use your MockTransport and skip real push logic
Why You Were Seeing the Exception
The JGitInternalException you encountered is almost certainly because JGit was trying to connect to a real remote repository (like origin) that doesn't exist in your local test environment or isn't accessible. Any of the methods above will prevent that remote lookup and let you test safely locally.
内容的提问来源于stack exchange,提问作者Enosh Bansode

