diff --git a/lib/manager/gradle/__snapshots__/index.spec.ts.snap b/lib/manager/gradle/__snapshots__/index.spec.ts.snap
index 68432b5d63d7ada7de63459ce2d7ddb397d8faeb..b979d1c73003e0aa60ea9c420d49545416403962 100644
--- a/lib/manager/gradle/__snapshots__/index.spec.ts.snap
+++ b/lib/manager/gradle/__snapshots__/index.spec.ts.snap
@@ -555,7 +555,7 @@ Array [
         "NO_PROXY": "localhost",
         "PATH": "/tmp/path",
       },
-      "timeout": 900000,
+      "timeout": 60000,
     },
   },
 ]
@@ -589,7 +589,7 @@ Array [
         "NO_PROXY": "localhost",
         "PATH": "/tmp/path",
       },
-      "timeout": 900000,
+      "timeout": 60000,
     },
   },
 ]
@@ -610,7 +610,7 @@ Array [
     },
   },
   Object {
-    "cmd": "docker run --rm --name=renovate_gradle --label=renovate_child -v \\"localDir\\":\\"localDir\\" -w \\"localDir\\" renovate/gradle bash -l -c \\"./gradlew --init-script renovate-plugin.gradle renovate\\"",
+    "cmd": "docker run --rm --name=renovate_gradle --label=renovate_child -v \\"localDir\\":\\"localDir\\" -w \\"localDir\\" renovate/gradle bash -l -c \\"gradle --init-script renovate-plugin.gradle renovate\\"",
     "options": Object {
       "cwd": "localDir",
       "encoding": "utf-8",
diff --git a/lib/manager/gradle/index.spec.ts b/lib/manager/gradle/index.spec.ts
index da3e7ab6345b521cc1d2a701d584d10c8520c838..2b6a35c060b55a2a07de14efcc4c5db4bebe8965 100644
--- a/lib/manager/gradle/index.spec.ts
+++ b/lib/manager/gradle/index.spec.ts
@@ -1,10 +1,8 @@
-import { toUnix } from 'upath';
-import _fs from 'fs-extra';
-import fsReal, { Stats } from 'fs';
+import fs from 'fs-extra';
+import * as upath from 'upath';
 import { exec as _exec } from 'child_process';
 import * as _os from 'os';
 import tmp, { DirectoryResult } from 'tmp-promise';
-import * as path from 'path';
 import { platform as _platform } from '../../platform';
 import { envMock, mockExecAll } from '../../../test/execUtil';
 import * as _env from '../../util/exec/env';
@@ -14,21 +12,23 @@ import * as _util from '../../util';
 import { ifSystemSupportsGradle } from './__testutil__/gradle';
 import * as _manager from '.';
 import { ExtractConfig } from '../common';
+import { GRADLE_DEPENDENCY_REPORT_FILENAME } from './gradle-updates-report';
+import { replacingSerializer } from '../../../test/util';
 
 const fixtures = 'lib/manager/gradle/__fixtures__';
-
-const config = {
-  localDir: 'localDir',
+const standardUpdatesReport = () =>
+  fs.readFile(`${fixtures}/updatesReport.json`, 'utf8');
+const emptyUpdatesReport = () =>
+  fs.readFile(`${fixtures}/updatesReportEmpty.json`, 'utf8');
+const multiProjectUpdatesReport = () =>
+  fs.readFile(`${fixtures}/MultiProjectUpdatesReport.json`, 'utf8');
+
+const baseConfig = {
   gradle: {
     timeout: 60,
   },
 };
 
-const updatesDependenciesReport = fsReal.readFileSync(
-  'lib/manager/gradle/__fixtures__/updatesReport.json',
-  'utf8'
-);
-
 const gradleOutput = {
   stdout: 'gradle output',
   stderr: '',
@@ -42,13 +42,11 @@ function resetMocks() {
 async function setupMocks() {
   resetMocks();
 
-  jest.mock('fs-extra');
   jest.mock('child_process');
   jest.mock('../../util/exec/env');
   jest.mock('../../platform');
   jest.mock('os');
 
-  const fs: jest.Mocked<typeof _fs> = require('fs-extra');
   const os: jest.Mocked<typeof _os> = require('os');
   const platform: jest.Mocked<typeof _platform> = require('../../platform')
     .platform;
@@ -58,42 +56,58 @@ async function setupMocks() {
 
   platform.getFile.mockResolvedValue('some content');
   env.getChildProcessEnv.mockReturnValue(envMock.basic);
-  await util.setUtilConfig(config);
+  await util.setUtilConfig(baseConfig);
 
-  return [require('.'), exec, fs, util, os];
+  return [require('.'), exec, util, os];
 }
 
 describe('manager/gradle', () => {
   describe('extractPackageFile', () => {
     let manager: typeof _manager;
     let exec: jest.Mock<typeof _exec>;
-    let fs: jest.Mocked<typeof _fs>;
     let util: jest.Mocked<typeof _util>;
     let os: jest.Mocked<typeof _os>;
     let docker: typeof _docker;
+    let config: ExtractConfig;
 
     beforeAll(async () => {
-      [manager, exec, fs, util, os] = await setupMocks();
+      [manager, exec, util, os] = await setupMocks();
       docker = require('../../util/exec/docker');
     });
 
     afterAll(resetMocks);
 
-    beforeEach(() => {
-      fs.readFile.mockResolvedValue(updatesDependenciesReport as any);
-      fs.mkdir.mockResolvedValue();
-      fs.exists.mockResolvedValue(true);
-      fs.stat.mockResolvedValue({
-        mode: 0o755,
-        isFile: () => true,
-      } as Stats);
+    beforeEach(async () => {
       exec.mockReset();
       docker.resetPrefetchedImages();
       os.platform.mockReturnValue('linux');
+
+      const gradleDir = await tmp.dir({ unsafeCleanup: true });
+      config = { ...baseConfig, localDir: gradleDir.path };
+      expect.addSnapshotSerializer(
+        replacingSerializer(upath.toUnix(gradleDir.path), 'localDir')
+      );
     });
 
+    async function initializeWorkingDir(
+      addGradleWrapper: boolean,
+      updatesReport: Promise<string> | string | null,
+      dir: string = config.localDir
+    ) {
+      if (addGradleWrapper) {
+        await fs.copy(`${fixtures}/gradle-wrappers/6`, dir);
+      }
+      if (updatesReport) {
+        await fs.writeFile(
+          `${dir}/${GRADLE_DEPENDENCY_REPORT_FILENAME}`,
+          await updatesReport
+        );
+      }
+    }
+
     it('should return gradle dependencies', async () => {
       const execSnapshots = mockExecAll(exec, gradleOutput);
+      await initializeWorkingDir(true, standardUpdatesReport());
 
       const dependencies = await manager.extractAllPackageFiles(config, [
         'build.gradle',
@@ -105,6 +119,7 @@ describe('manager/gradle', () => {
 
     it('should return gradle.kts dependencies', async () => {
       const execSnapshots = mockExecAll(exec, gradleOutput);
+      await initializeWorkingDir(true, standardUpdatesReport());
 
       const dependencies = await manager.extractAllPackageFiles(config, [
         'build.gradle.kts',
@@ -116,13 +131,8 @@ describe('manager/gradle', () => {
 
     it('should return empty if there are no dependencies', async () => {
       const execSnapshots = mockExecAll(exec, gradleOutput);
+      await initializeWorkingDir(true, emptyUpdatesReport());
 
-      fs.readFile.mockResolvedValue(
-        fsReal.readFileSync(
-          'lib/manager/gradle/__fixtures__/updatesReportEmpty.json',
-          'utf8'
-        ) as any
-      );
       const dependencies = await manager.extractAllPackageFiles(config, [
         'build.gradle',
       ]);
@@ -133,8 +143,8 @@ describe('manager/gradle', () => {
 
     it('should return empty if there is no dependency report', async () => {
       const execSnapshots = mockExecAll(exec, gradleOutput);
+      await initializeWorkingDir(true, null);
 
-      fs.exists.mockResolvedValue(false);
       const dependencies = await manager.extractAllPackageFiles(config, [
         'build.gradle',
       ]);
@@ -145,11 +155,12 @@ describe('manager/gradle', () => {
 
     it('should return empty if renovate report is invalid', async () => {
       const execSnapshots = mockExecAll(exec, gradleOutput);
-
-      const renovateReport = `
+      await initializeWorkingDir(
+        true,
+        `
         Invalid JSON]
-      `;
-      fs.readFile.mockResolvedValue(renovateReport as any);
+      `
+      );
 
       const dependencies = await manager.extractAllPackageFiles(config, [
         'build.gradle',
@@ -160,12 +171,7 @@ describe('manager/gradle', () => {
 
     it('should use repositories only for current project', async () => {
       const execSnapshots = mockExecAll(exec, gradleOutput);
-
-      const multiProjectUpdatesReport = fsReal.readFileSync(
-        'lib/manager/gradle/__fixtures__/MultiProjectUpdatesReport.json',
-        'utf8'
-      );
-      fs.readFile.mockResolvedValue(multiProjectUpdatesReport as any);
+      await initializeWorkingDir(true, multiProjectUpdatesReport());
 
       const dependencies = await manager.extractAllPackageFiles(config, [
         'build.gradle',
@@ -176,6 +182,7 @@ describe('manager/gradle', () => {
 
     it('should execute gradlew when available', async () => {
       const execSnapshots = mockExecAll(exec, gradleOutput);
+      await initializeWorkingDir(true, standardUpdatesReport());
 
       await manager.extractAllPackageFiles(config, ['build.gradle']);
       expect(execSnapshots).toMatchSnapshot();
@@ -183,6 +190,8 @@ describe('manager/gradle', () => {
 
     it('should execute gradlew.bat when available on Windows', async () => {
       const execSnapshots = mockExecAll(exec, gradleOutput);
+      await initializeWorkingDir(true, standardUpdatesReport());
+
       os.platform.mockReturnValue('win32');
 
       await manager.extractAllPackageFiles(config, ['build.gradle']);
@@ -191,7 +200,7 @@ describe('manager/gradle', () => {
 
     it('should execute gradle if gradlew is not available', async () => {
       const execSnapshots = mockExecAll(exec, gradleOutput);
-      fs.stat.mockRejectedValue(new Error());
+      await initializeWorkingDir(false, standardUpdatesReport());
 
       await manager.extractAllPackageFiles(config, ['build.gradle']);
       expect(execSnapshots).toMatchSnapshot();
@@ -199,7 +208,7 @@ describe('manager/gradle', () => {
 
     it('should return null and gradle should not be executed if no root build.gradle', async () => {
       const execSnapshots = mockExecAll(exec, gradleOutput);
-      fs.stat.mockRejectedValue(new Error());
+      await initializeWorkingDir(false, null);
 
       const packageFiles = ['foo/build.gradle'];
       expect(
@@ -212,6 +221,13 @@ describe('manager/gradle', () => {
 
     it('should return gradle dependencies for build.gradle in subdirectories if there is gradlew in the same directory', async () => {
       const execSnapshots = mockExecAll(exec, gradleOutput);
+      await initializeWorkingDir(true, standardUpdatesReport());
+      await fs.mkdirs(`${config.localDir}/foo`);
+      await initializeWorkingDir(
+        true,
+        standardUpdatesReport(),
+        `${config.localDir}/foo`
+      );
 
       const dependencies = await manager.extractAllPackageFiles(config, [
         'foo/build.gradle',
@@ -222,51 +238,48 @@ describe('manager/gradle', () => {
 
     it('should configure the renovate report plugin', async () => {
       const execSnapshots = mockExecAll(exec, gradleOutput);
+      await initializeWorkingDir(true, standardUpdatesReport());
 
       await manager.extractAllPackageFiles(config, ['build.gradle']);
 
-      expect(toUnix(fs.writeFile.mock.calls[0][0] as string)).toBe(
-        'localDir/renovate-plugin.gradle'
-      );
+      await expect(
+        fs.access(
+          `${config.localDir}/renovate-plugin.gradle`,
+          fs.constants.F_OK
+        )
+      ).resolves.toBe(undefined);
       expect(execSnapshots).toMatchSnapshot();
     });
 
     it('should use docker if required', async () => {
-      util.setUtilConfig({ ...config, binarySource: BinarySource.Docker });
+      const configWithDocker = { binarySource: BinarySource.Docker, ...config };
+      util.setUtilConfig(configWithDocker);
+      await initializeWorkingDir(false, standardUpdatesReport());
       const execSnapshots = mockExecAll(exec, gradleOutput);
 
-      const configWithDocker = {
-        binarySource: BinarySource.Docker,
-        ...config,
-      };
       await manager.extractAllPackageFiles(configWithDocker, ['build.gradle']);
 
       expect(execSnapshots).toMatchSnapshot();
     });
 
     it('should use docker even if gradlew is available', async () => {
-      util.setUtilConfig({ ...config, binarySource: BinarySource.Docker });
-      const execSnapshots = mockExecAll(exec, gradleOutput);
+      const configWithDocker = { binarySource: BinarySource.Docker, ...config };
+      util.setUtilConfig(configWithDocker);
+      await initializeWorkingDir(true, standardUpdatesReport());
 
-      const configWithDocker = {
-        binarySource: BinarySource.Docker,
-        ...config,
-        gradle: {},
-      };
+      const execSnapshots = mockExecAll(exec, gradleOutput);
       await manager.extractAllPackageFiles(configWithDocker, ['build.gradle']);
 
       expect(execSnapshots).toMatchSnapshot();
     });
 
     it('should use docker even if gradlew.bat is available on Windows', async () => {
+      const configWithDocker = { binarySource: BinarySource.Docker, ...config };
+      util.setUtilConfig(configWithDocker);
       os.platform.mockReturnValue('win32');
+      await initializeWorkingDir(true, standardUpdatesReport());
       const execSnapshots = mockExecAll(exec, gradleOutput);
 
-      const configWithDocker = {
-        binarySource: BinarySource.Docker,
-        ...config,
-        gradle: {},
-      };
       await manager.extractAllPackageFiles(configWithDocker, ['build.gradle']);
 
       expect(execSnapshots).toMatchSnapshot();
@@ -282,11 +295,11 @@ describe('manager/gradle', () => {
     });
     afterAll(resetMocks);
 
-    it('should update an existing module dependency', () => {
+    it('should update an existing module dependency', async () => {
       const execSnapshots = mockExecAll(exec, gradleOutput);
 
-      const buildGradleContent = fsReal.readFileSync(
-        'lib/manager/gradle/__fixtures__/build.gradle.example1',
+      const buildGradleContent = await fs.readFile(
+        `${fixtures}/build.gradle.example1`,
         'utf8'
       );
       // prettier-ignore
@@ -374,45 +387,41 @@ describe('manager/gradle', () => {
   });
 
   describe('executeGradle integration', () => {
-    const SUCCESS_FILE = 'success.indicator';
+    const SUCCESS_FILE_NAME = 'success.indicator';
     let workingDir: DirectoryResult;
     let testRunConfig: ExtractConfig;
+    let successFile: string;
 
     const manager = require('.');
 
     beforeEach(async () => {
       workingDir = await tmp.dir({ unsafeCleanup: true });
-      testRunConfig = { ...config, localDir: workingDir.path };
-      await _fs.copy(`${fixtures}/minimal-project`, workingDir.path);
-      await _fs.copy(`${fixtures}/gradle-wrappers/6`, workingDir.path);
+      successFile = '';
+      testRunConfig = { ...baseConfig, localDir: workingDir.path };
+      await fs.copy(`${fixtures}/minimal-project`, workingDir.path);
+      await fs.copy(`${fixtures}/gradle-wrappers/6`, workingDir.path);
 
       const mockPluginContent = `
 allprojects {
   tasks.register("renovate") {
     doLast {
-      new File('${SUCCESS_FILE}').write 'success'
+      new File('${SUCCESS_FILE_NAME}').write 'success'
     }
   }
 }`;
-      await _fs.writeFile(
-        path.join(workingDir.path, 'renovate-plugin.gradle'),
+      await fs.writeFile(
+        `${workingDir.path}/renovate-plugin.gradle`,
         mockPluginContent
       );
+      successFile = `${workingDir.path}/${SUCCESS_FILE_NAME}`;
     });
 
     ifSystemSupportsGradle(6).it(
       'executes an executable gradle wrapper',
       async () => {
-        const gradlew = await fsReal.promises.stat(
-          path.join(workingDir.path, 'gradlew')
-        );
+        const gradlew = await fs.stat(`${workingDir.path}/gradlew`);
         await manager.executeGradle(testRunConfig, workingDir.path, gradlew);
-        await expect(
-          fsReal.promises.readFile(
-            path.join(workingDir.path, SUCCESS_FILE),
-            'utf8'
-          )
-        ).resolves.toBe('success');
+        await expect(fs.readFile(successFile, 'utf8')).resolves.toBe('success');
       },
       120000
     );
@@ -420,20 +429,10 @@ allprojects {
     ifSystemSupportsGradle(6).it(
       'executes a not-executable gradle wrapper',
       async () => {
-        await fsReal.promises.chmod(
-          path.join(workingDir.path, 'gradlew'),
-          '444'
-        );
-        const gradlew = await fsReal.promises.stat(
-          path.join(workingDir.path, 'gradlew')
-        );
+        await fs.chmod(`${workingDir.path}/gradlew`, '444');
+        const gradlew = await fs.stat(`${workingDir.path}/gradlew`);
         await manager.executeGradle(testRunConfig, workingDir.path, gradlew);
-        await expect(
-          fsReal.promises.readFile(
-            path.join(workingDir.path, SUCCESS_FILE),
-            'utf8'
-          )
-        ).resolves.toBe('success');
+        await expect(fs.readFile(successFile, 'utf8')).resolves.toBe('success');
       },
       120000
     );
diff --git a/test/util.ts b/test/util.ts
index 72050b23b5805f09e0dd75c8232b882cb66cc976..7e20b32dc0efe7f9293e1d4e0e70412fbb8795a7 100644
--- a/test/util.ts
+++ b/test/util.ts
@@ -31,3 +31,21 @@ export function getName(file: string): string {
   const [, name] = /lib\/(.*?)\.spec\.ts$/.exec(file.replace(/\\/g, '/'));
   return name;
 }
+
+/**
+ * Can be used to search and replace strings in jest snapshots.
+ * @example
+ * expect.addSnapshotSerializer(
+ *     replacingSerializer(upath.toUnix(gradleDir.path), 'localDir')
+ * );
+ */
+export const replacingSerializer = (
+  search: string,
+  replacement: string
+): jest.SnapshotSerializerPlugin => ({
+  test: value => typeof value === 'string' && value.includes(search),
+  serialize: (val, config, indent, depth, refs, printer) => {
+    const replaced = (val as string).replace(search, replacement);
+    return printer(replaced, config, indent, depth, refs);
+  },
+});