Cross-platform file handling best practices
This document explains the best practices to assure consistent and stable file handling across test cases and environments.
Scenario​
A QA team is testing a web application that requires uploading test data files from different locations depending on the operating system. The test suite must run on Windows, macOS, and Linux without code duplication. Currently, the team maintains separate test files for each OS, which creates maintenance overhead and inconsistency. They need a single test case that automatically detects the OS and uses the appropriate file path and separator.
Purpose and strategic value​
| Purpose | Strategic Value |
|---|---|
| Unified Test Execution | Write one test case that automatically adapts to Windows, macOS, and Linux environments |
| Eliminate Code Duplication | Remove the need to maintain three separate test files for different platforms |
| Reduce Maintenance Overhead | Update test logic once instead of managing multiple platform-specific versions |
| Enable Seamless CI/CD Integration | Execute the same test suite across different OS agents in CI/CD pipelines without modification |
| Improve Portability | Ensure the project works immediately when moved to a different machine or environment |
Best practices steps​
- Consistent project structure: Organize test files in a consistent folder structure (e.g.,
Data/TestFiles/) - Relative data file paths: Store upload files in the project directory using relative paths
- KS installed on test machines: Ensure Katalon Studio is installed on Windows, macOS, and Linux machines
- Test object for file upload input field: Create a test object for the file upload input field
This guide walks you through these steps to make your test cases consistent across operating systems:
- Use
System.getProperty('os.name')to detect the operating system at runtime - Combine OS detection with
RunConfiguration.getProjectDir()andFile.separatorto handle path separators automatically across platforms - Implement conditional logic to handle OS-specific file paths and separators
- Store OS-specific values in variables for reusability throughout the test (Optional)
Step 1: Detect the operating system​
Create a test case that detects the OS using System.getProperty('os.name'):
// Detect the operating system
String osName = System.getProperty('os.name').toLowerCase()
// Log the detected OS for debugging
println("Detected OS: " + osName)
// Determine if running on Windows, macOS, or Linux
boolean isWindows = osName.contains('windows')
boolean isMac = osName.contains('mac')
boolean isLinux = osName.contains('linux')
println("Is Windows: " + isWindows)
println("Is macOS: " + isMac)
println("Is Linux: " + isLinux)
Results
- Test script detects operating system, and prints to console log:
- Windows:
Detected OS: windows 10(or similar) - macOS:
Detected OS: mac os x - Linux:
Detected OS: linux
- Windows:
Step 2: Build OS-specific file paths using relative paths​
Use RunConfiguration.getProjectDir() combined with File.separator to create portable paths:
import com.kms.katalon.core.configuration.RunConfiguration
// Get the project directory (works on all platforms)
String projectDir = RunConfiguration.getProjectDir()
// Use File.separator for platform-specific path separator
String fileSeparator = File.separator
// Build the relative path to test data
String testDataPath = projectDir + fileSeparator + 'Data' + fileSeparator + 'TestFiles' + fileSeparator + 'upload_file.txt'
println("Full file path: " + testDataPath)
Results:
- The combination ensures portability without hardcoding paths for data files:
RunConfiguration.getProjectDir()returns the absolute project path on any OSFile.separatorautomatically uses\\on Windows and/on macOS/Linux
Step 3: Implement OS-Specific logic for file upload​
Implement step 1 and 2 in your script, for a complete OS detection with file path handling in your test case:
import com.kms.katalon.core.configuration.RunConfiguration
import com.kms.katalon.core.webui.keyword.WebUiBuiltInKeywords as WebUI
// Step 1: Detect OS
String osName = System.getProperty('os.name').toLowerCase()
boolean isWindows = osName.contains('windows')
boolean isMac = osName.contains('mac')
boolean isLinux = osName.contains('linux')
// Step 2: Build file path using relative paths
String projectDir = RunConfiguration.getProjectDir()
String fileSeparator = File.separator
String testFilePath = projectDir + fileSeparator + 'Data' + fileSeparator + 'TestFiles' + fileSeparator + 'upload_file.txt'
// Step 3: Log OS and file path for verification
println("Running on OS: " + osName)
println("File path: " + testFilePath)
// Step 4: Apply OS-specific actions if needed
if (isWindows) {
println("Executing Windows-specific setup...")
// Windows-specific actions (e.g., driver configuration)
} else if (isMac) {
println("Executing macOS-specific setup...")
// macOS-specific actions
} else if (isLinux) {
println("Executing Linux-specific setup...")
// Linux-specific actions
}
WebUI.navigateToUrl('https://tus.io/demo')
// Step 5: Perform file upload using the portable path
WebUI.uploadFile(findTestObject('Object Repository/Upload_Input'), testFilePath)
// Step 6: Verify upload success
String uploadedFileName = WebUI.getAttribute(findTestObject('Object Repository/Upload_Input'), 'value')
println("Uploaded file: " + uploadedFileName)
Results:
- The test case detects OS and customizes paths accordingly for each file.
Step 4 (Optional): Store reusable OS detection logic in a Custom Keyword​
Instead of repeating step 1 and 2 across test cases, you can create a custom keyword and reuse it across multiple test cases:
// File: Keywords/OSDetection.groovy
package keywords
public class OSDetection {
static String getOSName() {
return System.getProperty('os.name').toLowerCase()
}
static boolean isWindows() {
return getOSName().contains('windows')
}
static boolean isMac() {
return getOSName().contains('mac')
}
static boolean isLinux() {
return getOSName().contains('linux')
}
static String getFilePath(String relativePath) {
String projectDir = RunConfiguration.getProjectDir()
String fileSeparator = File.separator
return projectDir + fileSeparator + relativePath.replace('/', fileSeparator)
}
}
Results
OSDetectionprovides methodsisWindows,isMac,isLinuxfor a simple, convenient OS checkOSDetection.getFilePathreturns customized path for your files, based on OS.
Sample implementation in a test case
import keywords.OSDetection
// Simple OS check
if (OSDetection.isWindows()) {
println("Running on Windows")
}
// Get portable file path
String filePath = OSDetection.getFilePath('Data/TestFiles/upload_file.txt')
WebUI.uploadFile(findTestObject('Upload_Input'), filePath)
// Navigate to application
WebUI.navigateToUrl('https://tus.io/demo')
// Perform file upload using the portable path
WebUI.uploadFile(findTestObject('Object Repository/Upload_Input'), testFilePath)
// Verify upload success
String uploadedFileName = WebUI.getAttribute(findTestObject('Object Repository/Upload_Input'), 'value')
println("Uploaded file: " + uploadedFileName)