有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java在日志或报表中嵌入方法的内容

在Java中,有没有一种通用的方法可以通过任何方式将方法的代码嵌入日志中?我在Cumber工作,尽管它倾向于(或者是?)糟糕的做法是,合规部门希望看到报告中打印的“Then”语句背后的断言(他们无法访问源代码)。写日志是很容易的,但是我怎么能以一种通用的方式在“@Then”后面的方法中读取所有内容呢

因此,让您了解一个示例方法:

 @Then("^my profile information is retrieved with success")
    public void validateProfileInformation() {
     assertThat(..).isEqualTo(..);
     assertThat(..).isEqualTo(..);
     assertThat(..).isEqualTo(..);
     assertThat(..).isEqualTo(..);
     assertThat(..).isEqualTo(..);
     assertThat(..).isEqualTo(..);
     if (this){
        x = y;
     }
}

需要在日志中写入的内容:

 SOME HEADER TEXT
 assertThat(..).isEqualTo(..);
 assertThat(..).isEqualTo(..);
 assertThat(..).isEqualTo(..);
 assertThat(..).isEqualTo(..);
 assertThat(..).isEqualTo(..);
 assertThat(..).isEqualTo(..);
 **Optionally:**
 if (this){
    x = y;
 }

所以我真的需要未执行的代码(当测试失败和通过时),而不需要结果。最好像通用方法或拦截器一样,这样就可以在整个项目中应用它,而不必将它添加到每个方法中。如能向正确方向推进,将不胜感激


共 (1) 个答案

  1. # 1 楼答案

    马文波姆

        <groupId>igb.so</groupId>
        <artifactId>SO-62882091-log-sourcecode</artifactId>
        <version>20.7.14</version>
    
        <url>https://stackoverflow.com/a/62904271/1744774</url>
        <developers>
            <developer>
                <name>Gerold 'Geri' Broser</name>
            </developer>
        </developers>
    
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <maven.compiler.source>11</maven.compiler.source>
            <maven.compiler.target>11</maven.compiler.target>
    
            <log4j.version>2.13.3</log4j.version>
            <slf4j.version>1.7.30</slf4j.version>
            <junit.version>5.6.2</junit.version>
        </properties>
    
        <dependencies>
    
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-api</artifactId>
                <version>${slf4j.version}</version>
            </dependency>
    
            <dependency>
                <groupId>org.apache.logging.log4j</groupId>
                <artifactId>log4j-core</artifactId>
                <version>${log4j.version}</version>
            </dependency>
    
            <dependency>
                <groupId>org.apache.logging.log4j</groupId>
                <artifactId>log4j-slf4j-impl</artifactId>
                <version>${log4j.version}</version>
            </dependency>
    
            <dependency>
                <groupId>org.junit.jupiter</groupId>
                <artifactId>junit-jupiter</artifactId>
                <version>${junit.version}</version>
                <scope>test</scope>
            </dependency>
    
        </dependencies>
    

    AbstractTestSourceErrorLogger

    package igb.so.logging;
    
    import java.util.Arrays;
    
    import org.slf4j.Logger;
    
    public abstract class AbstractTestSourceErrorLogger {
    
        protected static final String LF = System.getProperty( "line.separator" );
    
        protected final String testSourcePath;
        protected final Class<? extends Object> testClass;
        protected final Logger log;
        protected boolean withLineNumbers;
        
        protected int lineNo;
        protected boolean isInMethod;
        protected int codeBlockLevel;
    
        protected AbstractTestSourceErrorLogger( final Class<? extends Object> testClass, final Logger logger ) {
            this( "", testClass, logger, false );
        }
    
        protected AbstractTestSourceErrorLogger(
                final String testSourcePath, final Class<? extends Object> testClass, final Logger logger ) {
            this( testSourcePath, testClass, logger, false );
        }
    
        protected AbstractTestSourceErrorLogger(
                final Class<? extends Object> testClass, final Logger logger, final boolean withLineNumbers ) {
            this( "", testClass, logger, withLineNumbers );
        }
    
        protected AbstractTestSourceErrorLogger(
                final String testSourcePath, final Class<? extends Object> testClass,
                final Logger logger, final boolean withLineNumbers ) {
            this.testSourcePath = testSourcePath;
            this.testClass = testClass;
            log = logger;
            this.withLineNumbers = withLineNumbers;
        }
    
        /** Logs an {@link AssertionError} with the ERROR level. Afterwards logs the method body in which the error occurred.
         *
         * @param error - the error to log
         */
        public void error( final AssertionError error ) {
            error( error, withLineNumbers );
        }
    
        /** Logs an {@link AssertionError} with the ERROR level. Afterwards logs the method body in which the error occurred with optional line numbers.
         *
         * @param error - the error to log
         * @param withLineNumbers - <code>true</code> for equipping the logged source code with line numbers
         */
        public abstract void error( final AssertionError error, final boolean withLineNumbers );
    
        protected StackTraceElement failedTest( final AssertionError error ) {
            return Arrays.stream( error.getStackTrace() )
                    .filter( e -> e.getClassName().equals( testClass.getName() ) )
                    .findFirst().get();
        }
    
    } // AbstractTestSourceLogger
    

    SimpleTestSourceErrorLogger

    package igb.so.logging;
    
    import java.io.IOException;
    import java.nio.file.Files;
    import java.nio.file.Path;
    import java.nio.file.Paths;
    
    import org.slf4j.Logger;
    
    public class SimpleTestSourceErrorLogger extends AbstractTestSourceErrorLogger {
    
        public SimpleTestSourceErrorLogger(
                final Class<? extends Object> testClass, final Logger logger ) {
            super( testClass, logger );
        }
    
        public SimpleTestSourceErrorLogger(
                final String testSourcePath, final Class<? extends Object> testClass, final Logger logger ) {
            super( testSourcePath, testClass, logger, false );
        }
    
        public SimpleTestSourceErrorLogger(
                final Class<? extends Object> testClass, final Logger logger, final boolean withLineNumbers ) {
            super( "", testClass, logger, withLineNumbers );
        }
    
        public SimpleTestSourceErrorLogger(
                final String testSourcePath, final Class<? extends Object> testClass,
                final Logger logger, final boolean withLineNumbers ) {
            super( testSourcePath, testClass, logger, withLineNumbers );
        }
    
        @Override
        public void error( final AssertionError error, final boolean withLineNumbers ) {
            final StringBuilder sb = new StringBuilder();
    
            sb.append( error ).append( LF );
            final StackTraceElement failedTest = failedTest( error );
            final Path source = Paths.get( testSourcePath, failedTest.getClassName().replaceAll( "\\.", "/" ) + ".java" );
            sb.append( "  in method:" ).append( LF );
            lineNo = 1;
            try {
                Files.lines( source )
                        .forEach( line -> {
                            if ( line.strip().startsWith( String.format( "public void %s()", failedTest.getMethodName() ) ) )
                                isInMethod = true;
                            if ( isInMethod ) {
                                if ( line.contains( "{" ) )
                                    codeBlockLevel++;
                                if ( codeBlockLevel > 0 ) {
                                    final String format = withLineNumbers ? "  %d: %s%s%n" : "%2$s%3$s%n";
                                    sb.append( String.format( format, lineNo, line,
                                            lineNo == failedTest.getLineNumber() ? " // " + error.toString() : "" ) );
                                }
                                if ( line.contains( "}" ) )
                                    codeBlockLevel ;
                                if ( codeBlockLevel <= 0 ) {
                                    isInMethod = false;
                                }
                            }
                            lineNo++;
                        } );
                log.error( sb.toString() );
            }
            catch (final IOException e) {
                throw new RuntimeException( e );
            }
        } // error()
    
    } // SimpleTestSourceErrorLogger
    

    SimpleLoggerTest

    package igb.so;
    
    import static org.junit.jupiter.api.Assertions.assertNotNull;
    import static org.junit.jupiter.api.Assertions.assertTrue;
    
    import org.junit.jupiter.api.Test;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import igb.so.logging.SimpleTestSourceErrorLogger;
    
    public class SimpleLoggerTest {
    
        private static Logger log = LoggerFactory.getLogger( SimpleLoggerTest.class );
        private static SimpleTestSourceErrorLogger sLog = //
                new SimpleTestSourceErrorLogger( "src/test/java", SimpleLoggerTest.class, log, true );
    
        @Test
        public void testTrue() {
    
            try {
                assertTrue( true );
                assertTrue( false );
            }
            catch (final AssertionError e) {
                sLog.error( e );
                throw e;
            }
    
        } // testTrue()
    
        @Test
        public void testNotNull() {
    
            try {
                assertNotNull( new Object() );
                assertNotNull( null );
            }
            catch (final AssertionError e) {
                sLog.error( e, false );
                throw e;
            }
    
        } // testNotNull()
    
    } // SimpleLoggerTest
    

    JUnitEclipse输出控制台

    23:16:02.035 [main] ERROR igb.so.SimpleLoggerTest - org.opentest4j.AssertionFailedError: expected: <true> but was: <false>
      in method:
      18:   public void testTrue() {
      19: 
      20:       try {
      21:           assertTrue( true );
      22:           assertTrue( false ); // org.opentest4j.AssertionFailedError: expected: <true> but was: <false>
      23:       }
      24:       catch (final AssertionError e) {
      25:           sLog.error( e );
      26:           throw e;
      27:       }
      28: 
      29:   } // testTrue()
    
    23:16:02.111 [main] ERROR igb.so.SimpleLoggerTest - org.opentest4j.AssertionFailedError: expected: not <null>
      in method:
        public void testNotNull() {
    
            try {
                assertNotNull( new Object() );
                assertNotNull( null ); // org.opentest4j.AssertionFailedError: expected: not <null>
            }
            catch (final AssertionError e) {
                sLog.error( e, false );
                throw e;
            }
    
        } // testNotNull()
    

    mvn test输出

    ...
                               -
     T E S T S
                               -
    Running igb.so.SimpleLoggerTest
    23:25:25.956 [main] ERROR igb.so.SimpleLoggerTest - org.opentest4j.AssertionFailedError: expected: <true> but was: <false>
      in method:
      18:   public void testTrue() {
      19: 
      20:       try {
      21:           assertTrue( true );
      22:           assertTrue( false ); // org.opentest4j.AssertionFailedError: expected: <true> but was: <false>
      23:       }
      24:       catch (final AssertionError e) {
      25:           sLog.error( e );
      26:           throw e;
      27:       }
      28: 
      29:   } // testTrue()
    
    23:25:25.966 [main] ERROR igb.so.SimpleLoggerTest - org.opentest4j.AssertionFailedError: expected: not <null>
      in method:
        public void testNotNull() {
    
            try {
                assertNotNull( new Object() );
                assertNotNull( null ); // org.opentest4j.AssertionFailedError: expected: not <null>
            }
            catch (final AssertionError e) {
                sLog.error( e, false );
                throw e;
            }
    
        } // testNotNull()
    
    Tests run: 2, Failures: 2, Errors: 0, Skipped: 0, Time elapsed: 0.026 sec <<< FAILURE!
    igb.so.SimpleLoggerTest.testTrue()  Time elapsed: 0.023 sec  <<< FAILURE!
    org.opentest4j.AssertionFailedError: expected: <true> but was: <false>
        at org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:55)
        at org.junit.jupiter.api.AssertTrue.assertTrue(AssertTrue.java:40)
        at org.junit.jupiter.api.AssertTrue.assertTrue(AssertTrue.java:35)
        at org.junit.jupiter.api.Assertions.assertTrue(Assertions.java:162)
        at igb.so.SimpleLoggerTest.testTrue(SimpleLoggerTest.java:22)
    
    igb.so.SimpleLoggerTest.testNotNull()  Time elapsed: 0.001 sec  <<< FAILURE!
    org.opentest4j.AssertionFailedError: expected: not <null>
        at org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:39)
        at org.junit.jupiter.api.Assertions.fail(Assertions.java:109)
        at org.junit.jupiter.api.AssertNotNull.failNull(AssertNotNull.java:47)
        at org.junit.jupiter.api.AssertNotNull.assertNotNull(AssertNotNull.java:36)
        at org.junit.jupiter.api.AssertNotNull.assertNotNull(AssertNotNull.java:31)
        at org.junit.jupiter.api.Assertions.assertNotNull(Assertions.java:283)
        at igb.so.SimpleLoggerTest.testNotNull(SimpleLoggerTest.java:36)
    
    
    Results :
    
    Failed tests:   igb.so.SimpleLoggerTest.testTrue(): expected: <true> but was: <false>
      igb.so.SimpleLoggerTest.testNotNull(): expected: not <null>
    
    Tests run: 2, Failures: 2, Errors: 0, Skipped: 0
    ...
    

    PS:使用JUnit,因为我不熟悉Cucumber。但你明白了