2018년 8월 27일 월요일

모바일 자동화 tip - Android

appPackage, appActivity 찾기

  1. adb shell
  2. dumpsys window windows | grep -E ‘mCurrentFocus|mFocusedApp’
또는 adb logcat
실행 확인(cmd execution check)
:/> adb shell am start -n {appActivity}

디바이스 무선 연결
adb tcpip 5656
adb connect IP:5656
adb -s <device name> tcpip 5657 (2대 이상인 경우 device name 지정)

TestNG에서 테스트 순서 제어하기


public class TestNGTest3 {
 
    @BeforeClass
    public void beforeclass(){
        System.out.println("@BeforeClass TestNGTest3");
    }
     
    @Test
    public void test7(){
        System.out.println("test7");
        Assert.assertTrue(true);
    }
     
    @Test
    public void test2() throws Exception{
        System.out.println("test2");
        Assert.assertTrue(true);
    }
     
    @Test
    public void test15() throws Exception{
        System.out.println("test15");
        Assert.assertTrue(true);
    }
     
    @AfterClass
    public void afterclass(){
        System.out.println("@AfterClass TestNGTest3");
    }
}
[결과]

@BeforeClass TestNGTest3
test15
test2
test7
@AfterClass TestNGTest3
PASSED: test15
PASSED: test2
PASSED: test7


public class TestNGTest1 {

    @BeforeClass

    public void beforeclass(){
        System.out.println("@BeforeClass TestNGTest1");
    }

    @Test
    public void test12() throws Exception{
        System.out.println("Test12");
        Assert.assertTrue(true);
    }

    @Test
    public void test5(){
        System.out.println("Test5");
        Assert.assertTrue(true);
    }

    @Test
    public void test3(){
        System.out.println("Test3");
        Assert.assertTrue(true);
    }

    @AfterClass
    public void afterclass(){
        System.out.println("@AfterClass TestNGTest1");
    }
}
[결과]

@BeforeClass TestNGTest1
Test12
Test3
Test5
@AfterClass TestNGTest1
PASSED: test12
PASSED: test3
PASSED: test5

[해결책]

<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="TestNG Suite Name">
    <test name="TestNGTest" preserve-order="true">
        <classes>
            <class name="testng.TestNGTest1">
                <methods>
                    <include name="test3" />
                    <include name="test5" />
                    <include name="test12" />
                </methods>
            </class>

            <class name="testng.TestNGTest3">
                <methods>
                    <include name="test2" />
                    <include name="test7" />
                    <include name="test15" />
                </methods>
            </class>
        </classes>
    </test>
</suite>
[설명]
testng의 suite 파일에 preserve-order='true' 를 설정하고 해당 클래스의 test method의 순서를 지정해주면 된다.

[결과]
@BeforeClass TestNGTest1
Test3
Test5
Test12
@AfterClass TestNGTest1
@BeforeClass TestNGTest3
test2
test7
test15
@AfterClass TestNGTest3

※ 위 순서대로 사용하려면, dependsOnMethod를 사용하시면 안됩니다.

TestNG에서 2개 이상의 assert를 한꺼번에 처리하는 방법

개요

"@Test" 메소드에서 테스트 할 때 부득이하게 assert를 여러 번 해야 할 경우가 있다.
이 때 한꺼번에 처리해주지 않으면 첫번 째 assert에서 fail이 발생할 경우, 그 아래에 있는 assert 구문을 처리하지 않고 테스트가 종료되어 남아있는 assert 구문을 확인할 수 없다.
이를 해결하기 위한 방법을 정리한다.

내용

TestNG에서는 Hard assert / Soft Assert로 구분한다.
Hard Assert는 assert 시 fail이 발생하면 해당 테스트를 종료하는 것이고,
Soft assert는 assert 시 fail이 발생해도 로그에서는 fail이지만 테스트 결과는 pass로 해준다. 최종 결과를 확인하기 위해서는 아래와 같이 사용해야 한다.

Hard Assert


@Test
public void hardAssertTest(){
   Assert.assertFalse(2<1);
   System.out.println("Assertion Failed in Test 1");
   Assert.assertTrue(1<0);
   System.out.println("Assertion Failed in Test 2");
   Assert.assertEquals("Sample", "Sample");
   System.out.println("Assertion Passed in Test 3");
}
결과
Assertion Failed in Test 1
FAILED: hardAssertTest1
java.lang.AssertionError: expected [true] but found [false]
at org.testng.Assert.fail(Assert.java:94)
at org.testng.Assert.failNotEquals(Assert.java:513)
at org.testng.Assert.assertTrue(Assert.java:42)
at org.testng.Assert.assertTrue(Assert.java:52)
at testng.TestNGTest2.hardAssertTest1(TestNGTest2.java:13)
...
3번 line : PASS, 5번 line : FAIL이 발생하여 7번line의 assert를 하지 않고 hardAssertTest()의 테스트를 종료하고 빠져나온다. 테스트의 최종결과는 FAIL

Soft Assert 1


@Test
public void softAssertTest1(){
   SoftAssert sa= new SoftAssert();
   sa.assertTrue(2<1);
   System.out.println("Assertion Failed1");
   sa.assertFalse(1<2);
   System.out.println("Assertion Failed2");
   sa.assertEquals("Sample", "Failed");
   System.out.println("Assertion Failed3");
}
결과
Assertion Failed1
Assertion Failed2
Assertion Failed3
PASSED: softAssertTest1
assert는 fail이지만 테스트 결과는 PASS로 된다.

Soft Assert 2


@Test
public void softAssertTest2(){
   SoftAssert sa= new SoftAssert();
   sa.assertTrue(2<1);
   System.out.println("Assertion Failed1");
   sa.assertFalse(1<2);
   System.out.println("Assertion Failed2");
   sa.assertEquals("Sample", "Failed");
   System.out.println("Assertion Failed3");
   sa.assertAll();
}
결과
Assertion Failed1
Assertion Failed2
Assertion Failed3
FAILED: softAssertTest2
java.lang.AssertionError: The following asserts failed:
expected [true] but found [false],
expected [false] but found [true],
expected [Failed] but found [Sample]
at org.testng.asserts.SoftAssert.assertAll(SoftAssert.java:43)
at testng.TestNGTest2.softAssertTest2(TestNGTest2.java:54)
....
SoftAssert 객체를 생성한 후 - SoftAssert sa = new SoftAssert();
SoftAssert 객체로 assert를 모두 진행하고 난 뒤, 마지막에 "sa.assertAll()" 을 해주면 하나라도 fail이 발생 시 최종 테스트 결과는 FAIL로 된다.
assert를 모두 확인하고 테스트를 종료하므로 테스트 메소드에 assert 구문이 여러 개 일 경우 SoftAssert의 assertAll을 사용하자.

Logback 사용법

SLF4J란, Simple Logging Facade for Java의 약자로 Log4J의 개발자 Ceki Gülcü가 LogBack과 함께 개발한 Logging Facade 즉, 로깅에 대한 인터페이스 모음이라고 볼 수 있습니다.
LogBack이 바로 SLF4J의 Native 구현체이며 SLF4J를 사용하여 로깅 처리를 하면 실제 로그는 LogBack에서 출력하게 됩니다.
SLF4J에 대해 좀 더 자세히 알고 있으시면 공식 사이트(https://www.slf4j.org/) 에서 확인하세요
그리고 LogBack에 대한 메뉴얼은 https://logback.qos.ch/manual/index.html 에서 확인 가능합니다.

준비물

1.pom.xml에 logback 관련 의존성 추가

<dependencies>
   <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>${slf4j.version}</version>
      <exclusions>
         <exclusion>
            <artifactId>log4j</artifactId>
            <groupId>log4j</groupId>
         </exclusion>
         <exclusion>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
         </exclusion>
         <exclusion>
            <artifactId>common-logging</artifactId>
            <groupId>common-logging</groupId>
         </exclusion>
      </exclusions>
   </dependency>
   <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>${logback.version}</version>
      <exclusions>
         <exclusion>
            <artifactId>log4j</artifactId>
            <groupId>log4j</groupId>
         </exclusion>
         <exclusion>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
         </exclusion>
         <exclusion>
            <artifactId>common-logging</artifactId>
            <groupId>common-logging</groupId>
         </exclusion>
      </exclusions>
   </dependency>
</dependencies>
2. 설정파일(logback.xml) 추가
메인에 있는 코드가 실행될 때 적용하고 싶은 설정파일은  src/main/resource 밑에 두고, 테스트 단계에서 별도의 설정파일을 적용하고 싶으면 src/test/resource 밑에 둔다.
1) 로그 레벨
TRACE → DEBUG → INFO → WARN → ERROR 의 로그 레벨이 있고, 설정파일에서 설정 레벨 이상의 로그를 출력할 수 있다.
예) 레벨 : INFO로 설정하면 TRACE, DEBUG 레벨의 로그는 출력되지 않는다.

2) Appender
로그를 출력할 위치, 출력 형식등을 지정할 때 사용된다.
기본적인 Appender로는 ConsolAppender, FileAppender, RollingFileAppender가 있다.
ConsolAppender : 로그를 콘솔에 출력시킨다.
FileAppender : 로그의 내용을 지정된 파일에 기록한다.
RollingFileAppender : 지정된 패턴에 따라 로그가 파일에 기록하도록 하여 대량의 로그를 효과적으로 기록할 때 사용된다.

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="30 seconds">
   <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
      <encoder>
         <pattern>[%d{yyyy-MM-dd HH:mm:ss}] [%-5p] %C.%M[%L] %m%n</pattern>
      </encoder>
   </appender>
   <root level="debug">
      <appender-ref ref="STDOUT" />
   </root>
</configuration>
3. 코드 예

public class LogSample {
    private static final Logger logger = LoggerFactory.getLogger(LogSample.class);
    public static void main(String args[]){
  String stringMsg = "Test";
  int integerMsg = 123;
  logger.trace("trace");
  logger.debug("debug");
  logger.debug("debug {} {}", stringMsg, integerMsg);
  logger.info("info");
  logger.warn("warn");
  logger.error("error");
    }
}

결과