使用testng框架和log4j为每个测试类保存唯一的日志

cvxl0en2  于 2021-06-29  发布在  Java
关注(0)|答案(1)|浏览(390)

我有一个自动化项目(java,maven with testng,log4j)。我正在尝试为每个测试类创建日志文件(logintest将创建logintest.log,hometest将创建hometest.log,等等),为此我实现了自己的日志机制,但在运行结束时,我只得到最后一个类测试日志文件(对于运行的最后一个测试类)。
这就是我的逻辑:

public class TestLogger extends LoggerFormat {

    private static final DateTimeFormatter TIMESTAMP_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    private static final ZoneId DEFAULT_ZONE_ID = ZoneId.of(EnvConf.getDefaultTimeZone());
    private final ThreadLocal<Map<String, List<String>>> testsLogMap = new ThreadLocal<>();

    public void info(ITestContext context, String messageFormat, Object... args) {
        String msg = handleFormatMsg(messageFormat, args);
        super.info(msg);
        log(Level.INFO, context, msg);
    }

    public void error(ITestContext context, Throwable t, String messageFormat, Object... args) {
        String msg = handleFormatMsg(messageFormat, args);
        super.error(msg, t);
        log(Level.ERROR, context, msg, t);
    }

    public void error(ITestContext context, String messageFormat, Object... args) {
        String msg = handleFormatMsg(messageFormat, args);
        super.error(msg);
        log(Level.ERROR, context, msg);
    }

    public void warn(ITestContext context, String messageFormat, Object... args) {
        String msg = handleFormatMsg(messageFormat, args);
        super.warn(msg);
        log(Level.WARN, context, msg);
    }

    public void warn(ITestContext context, Throwable t, String messageFormat, Object... args) {
        String msg = handleFormatMsg(messageFormat, args);
        super.warn(msg, t);
        log(Level.WARN, context, msg, t);
    }

    public void debug(ITestContext context, String messageFormat, Object... args) {
        String msg = handleFormatMsg(messageFormat, args);
        super.debug(msg);
        if (LoggerFactory.isDebug()) {
            log(Level.DEBUG, context, msg);
        }
    }

    public void debug(ITestContext context, Throwable t, String messageFormat, Object... args) {
        String msg = handleFormatMsg(messageFormat, args);
        super.debug(msg, t);
        if (LoggerFactory.isDebug()) {
            log(Level.DEBUG, context, msg, t);
        }
    }

    private void log(Level level, ITestContext context, Object message, Throwable t) {
        message = String.format("%s\n%s", message, throwableToString(t));
        log(level, context, message);
    }

    private void log(Level level, ITestContext context, Object message) {
        Map<String, List<String>> logsMap = getLogsMap();
        if (!logsMap.containsKey(context.getName())) {
            logsMap.put(context.getName(), new ArrayList<>());
        }

        logsMap.get(context.getName()).add(formatMsg(message, level));
        if (level.toInt() != Level.DEBUG.toInt()) {
            Reporter.log((String) message, 0);
        }
    }

    private static String formatMsg(Object message, Level level) {
        LocalDateTime dateTime = LocalDateTime.now(DEFAULT_ZONE_ID);
        return String.format("[%s][%s]%s",
                TIMESTAMP_FORMAT.format(dateTime),
                level, message);
    }

    public List<String> getAndDeleteLogsByTest(String testName) {
        return getLogsMap().remove(testName);
    }

    private Map<String, List<String>> getLogsMap() {
        if (testsLogMap.get() == null) {
            testsLogMap.set(new HashMap<>());
        }
        return testsLogMap.get();
    }

    private static String throwableToString(Throwable t) {
        StringBuilder builder = new StringBuilder();
        for (StackTraceElement traceElement : t.getStackTrace()) {
            builder.append(traceElement.toString()).append('\n');
        }
        return builder.toString();
    }

    private static String handleFormatMsg(String message, Object... args) {
        if (args.length == 0 && message.contains("%")) {
            message = message.replaceAll("%", "%%");
        }
        return String.format(message, args);
    }
}

这是我的basetest类:

@Listeners({NeoTestListener.class})
public class BaseTest {

    private static final Browser BROWSER = Browser.valueOf(EnvConf.getProperty("ui.browser.type"));
    private static final File SCREENSHOTS_FOLDER = new File(EnvConf.getProperty("test_output.screenshots.folder"));
//    private static final File DOWNLOADS_FOLDER = new File(EnvConf.getProperty("workspace.tests.downloads"));
    private static final File DOWNLOADS_FOLDER = new File(EnvConf.getProperty("test_output.logs.folder"));
    private static final String ADMIN_USERNAME = EnvConf.getProperty("hackeruso.admin.user.email");
    private static final String ADMIN_PASSWORD = EnvConf.getProperty("hackeruso.admin.user.password");

    protected static DriverWrapper driver;
    protected LoginPage loginPage;
    protected Date testStartTime;
    protected ITestContext context;
    protected TopBar topBar;
    protected final File testTempFolder;

    static {
        if (!SCREENSHOTS_FOLDER.exists()) {
            FileUtil.createFolder(SCREENSHOTS_FOLDER, true);
        }

        if(!DOWNLOADS_FOLDER.exists()) {
            FileUtil.createFolder(DOWNLOADS_FOLDER, false);
        }
    }

    protected static String randSuffix(String prefix){
        return prefix + "_" + String.valueOf(System.nanoTime()).substring(9);
    }

    public BaseTest() {
        this.testTempFolder = new File(DOWNLOADS_FOLDER, randSuffix(getClass().getSimpleName()));
        FileUtil.createFolder(testTempFolder, false);
//        testTempFolder.deleteOnExit();
    }

    @BeforeClass
    public final void baseSetup(ITestContext context) throws IOException {
        this.context = context;
        driver = DriverWrapper.open(BROWSER, DOWNLOADS_FOLDER);
        loginPage = new LoginPage(driver);
        info("<!!! '%s' START !!!>" , context.getName());
        testStartTime = new Date();
        this.context.setAttribute("test_start_time", testStartTime);
        info("testStartTime=[%s]" , testStartTime);
    }

    private void printBrowserLog() {

        List<LogEntry> serverLogLines = driver.manage().logs().get(LogType.BROWSER).getAll();
        if (serverLogLines.size() > 0) {
            Log.i("<---------Browser [SERVER] log start--------->");
            for (LogEntry entry : serverLogLines) {
                Log.e(entry.toString());
            }
            Log.i("<---------Browser [SERVER] log end------------>");
        }
    }

    @AfterClass
    public final void baseTeardown(ITestContext context) {
        Date testEndTime = new Date();
        if (driver != null) {
            printBrowserLog();
            driver.quit();
        }
        info("<!!! '%s' END !!!>" , context.getName());
        info("testEndTime=[%s]" , testEndTime);
    }

    public static DriverWrapper getDriver() {
        return driver;
    }

    protected void info(String message , Object...args){
        TESTS_LOG.info(context , message , args);
    }

    public void error(Throwable t , String messageFormat , Object...args) {
        TESTS_LOG.error(context , t , messageFormat , args);
    }

    public void error(String messageFormat , Object...args) {
        TESTS_LOG.error(context , messageFormat , args);
    }

    protected void warn(String messageFormat , Object...args) {
        TESTS_LOG.warn(context , messageFormat , args);
    }

    public void warn(Throwable t ,String messageFormat , Object...args) {
        TESTS_LOG.warn(context , t , messageFormat , args);
    }

    protected void debug(String messageFormat , Object...args) {
        TESTS_LOG.debug(context , messageFormat , args);
    }

    public void debug(Throwable t , String messageFormat , Object...args) {
        TESTS_LOG.debug(context , t , messageFormat , args);
    }
}

这是我的听众:

public class NeoTestListener implements ITestListener {
    private final File SCREENSHOTS_FOLDER = new File(EnvConf.getProperty("test_output.screenshots.folder"));
    private static final SimpleDateFormat FOLDER_NAME_FORMAT = new SimpleDateFormat("dd_MM_HH_mm_ss");
    private static final SimpleDateFormat LOG_NAME_FORMAT = new SimpleDateFormat("dd_MM_HH_mm_ss");
    private static final File TESTS_LOGS_FOLDER = new File(EnvConf.getProperty("test_output.logs.folder"));

    static {
        if (!TESTS_LOGS_FOLDER.exists()) {
            FileUtil.createFolder(TESTS_LOGS_FOLDER, true);
        }
    }

    private static String getTestMethodName(ITestResult iTestResult){
        return iTestResult.getMethod().getConstructorOrMethod().getName();
    }

    @Attachment
    public byte[] saveFailureScreenShot(DriverWrapper driver){
        return driver.getScreenshotAsByte();
    }

    @Attachment(value = "{0}", type = "text/plain")
    public static String saveTextLog(String message){
        return message;
    }

    @Override
    public void onStart(ITestContext context) {
        context.setAttribute("WebDriver", getDriver());

    }

    @Override
    public void onFinish(ITestContext context) {
    }

    @Override
    public void onTestStart(ITestResult result) {
        TESTS_LOG.info(result.getName() +" " +  result.getTestClass() );
//        TESTS_LOG.info("[Test: " + getTestClassName(result.getTestContext())+ " Started]");
    }

    @Override
    public void onTestSuccess(ITestResult result) {
    }

    @Override
    public void onTestFailure(ITestResult result) {
        TESTS_LOG.error(String.format("I am in onTestFailure method:=[%s] failed", getTestMethodName(result)));
        Object testClass = result.getInstance();
        DriverWrapper driver = getDriver();
        takeScreenshot(getTestMethodName(result));

        //Allure ScreenShot and SaveTestLog
        TESTS_LOG.info(String.format("Screenshot for class=[%s], method=[%s]", getTestClassName(result.getTestContext()), getTestMethodName(result)));
        saveFailureScreenShot(driver);
        try {
            saveLogTextFile(result);
        } catch (IOException e) {
            e.printStackTrace();
        }
        saveTextLog(getTestMethodName(result) + " failed and screenshot taken!");
    }

    @Attachment
    private byte[] saveLogTextFile(ITestResult result) throws IOException {
        return saveToLogFile(result.getTestContext());
    }

    @Override
    public void onTestSkipped(ITestResult result) {
    }

    @Override
    public void onTestFailedButWithinSuccessPercentage(ITestResult result) {
    }

    @Override
    public void onTestFailedWithTimeout(ITestResult result) {
    }

    private void takeScreenshot(String filePrefix){
        File dest = new File(SCREENSHOTS_FOLDER , filePrefix + "_" + FOLDER_NAME_FORMAT.format(new Date()) + ".png");
        takeScreenshot(dest, getDriver());
    }

    private void takeScreenshot(File destFile, DriverWrapper driver){
        File scrFile = driver.getScreenshotAsFile();
        Path src = Paths.get(scrFile.toURI());
        Path dest = Paths.get(destFile.toURI());
        try {
            Files.copy(src, dest , StandardCopyOption.REPLACE_EXISTING);
            TESTS_LOG.info("[[ATTACHMENT|" + destFile.getAbsolutePath() + "]]");
        } catch (IOException e) {
            TESTS_LOG.error("Failed to save screen shot at file: " + destFile.getName());
            TESTS_LOG.error(e.getMessage());
        }
    }

    private byte[] saveToLogFile(ITestContext context) throws IOException {
        File logFile = createLogFile(context);
        boolean created = FileUtil.createNewFile(logFile);

        if(created){
            List<String> testLogLines = TESTS_LOG.getAndDeleteLogsByTest(context.getName());
            if(testLogLines == null){
                TESTS_LOG.error(context, "test=[%s] don't have any log lines!" , context.getName());
            }else{
                FileUtil.writeToFile(logFile.getAbsolutePath(), testLogLines);
            }
        }else{
            TESTS_LOG.error(context, " failed to create test log file=[%s]", logFile.getAbsolutePath());
        }

        return FileUtils.readFileToByteArray(logFile);
    }

    private static File createLogFile(ITestContext context){
        return new File(TESTS_LOGS_FOLDER, String.format("%s_%s.log",getTestClassName(context), LOG_NAME_FORMAT.format(context.getStartDate())));
    }

    private static String getTestClassName(ITestContext context){
        return context.getAllTestMethods()[0].getInstance().getClass().getSimpleName();
    }

}

这是我的环境中的类测试示例:

public class ForgotPasswordTest extends BaseTest {
    private String verifyEmailURL = "";
    private static final String AUTOMATION_EMAIL= EnvConf.getProperty("automation.email.user");
    private static final String AUTOMATION_EMAIL_PASSWORD=EnvConf.getProperty("automation.email.password");
    private static final String AUTOMATION_WEBAPP_USER = "AUTOMATION_TESTER";
    private  ResetPasswordPage rpp;
    private final static String NEW_PASSWORD = "1Qaz2wsx3edc";
    private final static String ENVIRONMENT_BASE_URL = EnvConf.getProperty("base.url");

    @BeforeClass
    public void setup() {
        topBar = new TopBar(driver);
        rpp = new ResetPasswordPage(driver);
    }

    @Test(priority = 1)
    public void navigateToLoginPage(){
        loginPage.navigateAndVerify();
    }

    @Test(priority=2)
    public void sendChangePasswordInstructions() {
        ForgotPasswordPage fpp = loginPage.clickAndVerifyForgotPasswordButtonAction();
        fpp.sendForgotPasswordInstructions(AUTOMATION_EMAIL);
        Assert.assertTrue(loginPage.getForgotMsgAlertText().contains("Thank You, An Email Has Been Send"));
        info("Sending forget password instructions phase is successful!");
    }

    @Test(priority=3)
    public void verifyEmail(){
        verifyEmailURL = "";
        String regex = "href=\"([^\"]*)" ;
        String from = "<SOME_URL>";
        String subject = getSubject();
        String msg = MailHelper.getMessagesFromGmail( AUTOMATION_EMAIL, AUTOMATION_EMAIL_PASSWORD, from, subject, testStartTime);
        Pattern linkPattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
        Matcher pageMatcher = linkPattern.matcher(msg);
        while (pageMatcher.find()) {
            if (pageMatcher.group(1).contains("reset-password")) {
                verifyEmailURL = pageMatcher.group(1);
                verifyEmailURL = ENVIRONMENT_BASE_URL.concat("/").concat(verifyEmailURL.split("/")[3]);
                info("Verify URL: " + verifyEmailURL);
            }
        }

        info("Verifying email address is successful!");

    }

    @Test(priority = 4)
    public void navigateToResetPasswordScreen(){
        navigateTo(verifyEmailURL);
    }

    @Test(priority=5)
    public void connectToUpdateNewPassword() {

        rpp.changeNewPassword(NEW_PASSWORD);
        info("Changing password is successful!");
    }

    @Test(priority=6)
    public void verifyPasswordChanged() {
        signIn(AUTOMATION_EMAIL, NEW_PASSWORD, true);
        assertTrue(topBar.verifyExistenceTopBarNavigationItem(TopRightNavBarItem.SUPPORT));
        info(String.format("Password for user=[%s] changed successfully", AUTOMATION_WEBAPP_USER));

    }

    private String getSubject(){
        return "Reset Password";
    }

}

每次我用 mvn clean test 我无法保存每个测试类的日志它总是保存上次运行的测试类和其他未按预期保存的日志文件。
少了什么?我试图寻找一个解决办法,并尝试了各种行动,但我没有得到预期的结果。

laik7k3q

laik7k3q1#

maven surefire插件具有以下参数 <redirectTestOutputToFile> 在中创建以下文件 target/surefire-reports 除了这里的测试项目: igb.so.so65465538.FirstTest-output.txt :

println(): First test...
22:32:25.537 [main] INFO igb.so.so65465538.FirstTest - log.info():  First test...
``` `igb.so.so65465538.SecondTest-output.txt` :

println(): Second test...
22:32:25.561 [main] INFO igb.so.so65465538.SecondTest - log.info(): Second test...

相关问题