SalesForce開発のTips(備忘録)

SalesForce Apexのテストの備忘録

コードカバー率の調査

開発者コンソールの [Query Editor]タブで[Use Tooling API] をチェックして、下記A or Bを実行 f:id:TheManwiththeYellowHat:20190801131638p:plain

  • A.クラス単位で見たい場合
  SELECT ApexClassOrTrigger.Name, NumLinesCovered, NumLinesUncovered 
  FROM ApexCodeCoverageAggregate 
  WHERE ApexClassOrTrigger.Name = 'ApexClassName'
  • B.メソッド単位で見たい場合
SELECT ApexTestClass.Name,TestMethodName,NumLinesCovered,NumLinesUncovered 
FROM ApexCodeCoverage 
WHERE ApexClassOrTrigger.Name = 'ApexClassName'

SalesForce エラーハンドリングの備忘録

参考
Error Handling Best Practices for Lightning and Apex | Developer Force Blog
exception handling best practises - Salesforce Developer Community

【CircleCI】CircleCI 2.0でE2Eテスト(Kotlin・Junit・Selenium・Selenide)を実行してみた

CircleCiでSelenideを実行してみた

f:id:TheManwiththeYellowHat:20190718122924p:plain

ソースはこちら
github.com

環境・言語

  • OS
  • language
    • kotlin 1.3.31

前提条件

  • Homebrewがインストールされている(Homebrew 2.1.6)
  • gradleがインストールされている(Gradle 5.5)
  • javaがインストールされている(openjdk 11.0.2 2018-10-16)
  • githubにログインできる(登録している)
  • githubで空のリポジトリを作成している

プロジェクト作成(gradle)

mkdir hoge
cd hoge
gradle init --type kotlin-application

build.gradle(上記gradle initにて生成されたファイルを修正)

plugins {
    id 'org.jetbrains.kotlin.jvm' version '1.3.31'
    id 'application'
}

apply plugin: 'kotlin'
apply plugin: 'java'
apply plugin: 'idea'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
    implementation 'com.codeborne:selenide:5.2.4'
    testImplementation 'org.jetbrains.kotlin:kotlin-test'
    testImplementation 'org.jetbrains.kotlin:kotlin-test-junit'
}

テストクラス(/src/test/kotlin/e2e/test/MainTest.kt)

import kotlin.test.Test
import kotlin.test.assertTrue

class MainTest {
    @Test
    fun mainTest() {
        // ChromeDriver を headless モードで利用
        Configuration.browser = WebDriverRunner.CHROME
        Configuration.headless = true
        Configuration.reportsFolder = "test-result/reports"
        Configuration.browserSize = "1024x768"


        // Googleトップページ
        // "selenide"を検索
        open("https://www.google.co.jp/")
        `$`("input[type=text]").`val`("selenide").pressEnter()

        // 検索ページ
        // Selenideの公式ページをクリック
        `$`(byText("Selenide: concise UI tests in Java")).click()

        // Selenide公式ページ
        // 「What is Selenide?」という文言があることを確認
        `$`("body").shouldHave(text("What is Selenide?"))
    }
}

githubリポジトリにpush

git init
git remote add origin {github-target-repository}
git commit -m 'first commit'
git push origin master

Circle Ci に登録

circleci.com

Circle Ci config.yml作成

上記のプロジェクト直下で

touch .circleci/config.yml
  • .circleci/config.yml
version: 2
jobs:
  build:
    docker:
      - image: circleci/openjdk:11.0.2-jdk-browsers
    working_directory: ~/repo
    steps:
      - checkout
      - restore_cache:
          keys:
            # when lock file changes, use increasingly general patterns to restore cache
            - gradle-repo-v1-{{ .Branch }}-{{ checksum "build.gradle" }}
            - gradle-repo-v1-{{ .Branch }}-
            - gradle-repo-v1-
      - run:
          name: Library check
          command: |
            gradle dependencies
      - save_cache:
          paths:
            - ~/.gradle
          key: gradle-repo-v1-{{ .Branch }}-{{ checksum "build.gradle" }}
      - run:
          name: Run Tests
          command: gradle test
      - run:
          name: Save test results
          command: |
            mkdir -p ~/test-results/junit/
            find . -type f -regex ".*/build/test-results/.*xml" -exec cp -p {} ~/test-results/junit/ \;
            mkdir -p ~/test-results/reports/
            find . -type d -regex ".*/build/reports" -exec cp -rp {} ~/test-results/ \;
          when: always
      - store_test_results:
          path: ~/test-results
      - store_artifacts:
          path: ~/test-results/junit
      - store_artifacts:
          path: ~/test-results/reports
workflows:
  version: 2
  # push時のテスト実行用(workflowを使用すると、このworkflow(triggersの設定がなくjobを指定した)がないとpush時にjobが実行されない)
  normal_workflow:
    jobs:
      - build
  # スケジュールテスト実行用
  schedule_workflow:
    triggers:
      - schedule:
          cron: "1 3 1 * *" # UTCで記述。-9hours
          filters:
            branches:
              only:
                - master
    jobs:
      - build

CircleCI CLIインストール

brew install circleci

下記を参照
circleci.com

  • .circleci/config.ymlのチェック
circleci config validate

Config file at .circleci/config.yml is valid.
が出力されればOK。それ以外はエラーメッセージに書かれた内容に沿って対応。

  • ローカルで.circleci/config.ymlのテスト
circleci local execute --job build

Circle Ci にプロジェクト追加

f:id:TheManwiththeYellowHat:20190718114507p:plain

f:id:TheManwiththeYellowHat:20190718114530p:plain

normal_workflowの設定があることにより、上記でjobが実行される

結果の確認

f:id:TheManwiththeYellowHat:20190718115405p:plain

f:id:TheManwiththeYellowHat:20190718115409p:plain

f:id:TheManwiththeYellowHat:20190718115452p:plain

f:id:TheManwiththeYellowHat:20190718115503p:plain

まとめ

circleciのdocker imageが良いですね。
circleci/openjdk:11.0.2-jdk-browsers

無料枠で十分使えるので、楽だしこれから機会があればどんどん使いたいなぁ
250分/週かな?...
Usage Plan - CircleCI

ただし、下記のようなIPの制限があるので、それがネックになる場合は他が良さそうです。
IP アドレスのホワイトリスト登録 – CircleCI Japanese Support Center

参考

CircleCIのドキュメントへようこそ - CircleCI Gradle User Manual

 

 

intelliJでbuild Project時にwebpackのビルドも実行させてみた

intelliJのbuild / runアクションをgradleに委任

intelliJでgradleプロジェクトのビルド時にwebpackのビルドも実行したかったのでbuild.gradleにnpm installnpm run build(webpack)を実行する処理をbuild.gradleに実装し、毎ビルド時にbuilde.gradleが読み込まれるように設定してみた。

環境・言語

  • IDE
  • backend-framework
    • Spring boot 2
  • backend-language
    • kotlin
  • frontend-framework
    • vue.js
  • frontend-language

gradleプロジェクト追加したファイル

  • /package json
{
  "name": "hogehoge",
  "version": "1.0.0",
  "description": "hoge",
  "repository": {
    "type": "git",
    "url": "hogehoge.git"
  },
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.3.4",
    "babel-cli": "^6.26.0",
    "babel-loader": "^8.0.5",
    "babel-plugin-transform-runtime": "^6.23.0",
    "babel-preset-env": "^1.7.0",
    "copy-webpack-plugin": "^5.0.0",
    "css-loader": "^2.1.1",
    "lite-server": "^2.4.0",
    "vue-html-loader": "^1.2.4",
    "vue-loader": "^15.7.0",
    "vue-style-loader": "^4.1.2",
    "webpack": "^4.29.6",
    "webpack-cli": "^3.2.3"
  },
  "dependencies": {
    "vue": "^2.6.8",
    "vue-router": "^3.0.2"
  },
  "scripts": {
    "build": "webpack",
  }
}
  • /webpack.config.js
const path = require('path');
const { VueLoaderPlugin } = require('vue-loader');

module.exports = {
    mode: "development",
    entry: {
        console: path.join(__dirname, 'src', 'main', 'node', 'pages', 'console', 'main.js'),
    },
    output: {
        path: path.join(__dirname, 'src', 'main', 'resources', 'static', 'js'),
        filename: '[name].bundle.js'
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    'style-loader',
                    {loader: 'css-loader', options: {url: false}},
                ]
            },
            {
                test: /\.vue$/,
                use: [{loader: 'vue-loader'}]
            }
        ]
    },
    resolve: {
        extensions: ['.js', '.vue'],
        modules: [
            "node_modules"
        ],
        alias: {
            vue: 'vue/dist/vue.common.js'
        }
    },
    devtool: 'source-map',
    plugins: [
        new VueLoaderPlugin()
    ]
};
  • /build.gradle
plugins {
    id 'org.springframework.boot' version '2.1.2.RELEASE'
    id 'org.jetbrains.kotlin.jvm' version '1.2.71'
    id 'org.jetbrains.kotlin.plugin.spring' version '1.2.71'
}

apply plugin: 'io.spring.dependency-management'

bootJar{
    archiveName "hogehoge.jar"
    launchScript()
}

group = 'test.hogehoge'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    implementation 'org.springframework.boot:spring-boot-starter-data-redis'
    implementation 'org.springframework.session:spring-session-data-redis'
    implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'com.fasterxml.jackson.module:jackson-module-kotlin'
    implementation 'org.jetbrains.kotlin:kotlin-reflect'
    implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
    implementation 'org.mariadb.jdbc:mariadb-java-client:2.4.0'
    runtimeOnly 'org.springframework.boot:spring-boot-devtools'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'org.springframework.security:spring-security-test'
}

compileKotlin {
    kotlinOptions {
        freeCompilerArgs = ['-Xjsr305=strict']
        jvmTarget = '1.8'
    }
}

compileTestKotlin {
    kotlinOptions {
        freeCompilerArgs = ['-Xjsr305=strict']
        jvmTarget = '1.8'
    }
}

task npmRunBuild {
    doLast {
        def npm = System.getProperty('os.name').contains('Windows') ? 'cmd /c npm' : 'npm'
        if (file('./node_modules').exists() ==  false) {
            "${npm} install".execute().waitForProcessOutput(System.out, System.err)
        }
        "${npm} run build".execute().waitForProcessOutput(System.out, System.err)
    }
}
processResources.dependsOn npmRunBuild

動作確認

この状態でintelliJのBuild Project、もしくはRun Applicationを実行!
実行前には存在しなかった/node_modulespackage-lock.jsonが生成されました。

まとめ

vue.js側を更新した際にいちいち npm run build を実行しなければならないところをrunのみで、 全てbuildされて動作確認できるようになりました。

しがないエンジニアの自己紹介

こんにちはこんばんは

自己紹介

僕は既婚子供(2歳)がいる現在32歳のしょーもないエンジニアです。

これまではjava,php,ruby,android(java),ios(objective-c)など広く?浅くやってきたので、それぞれプロ級と言えるものではないのかもと不安に駆られています。

そんな感じでまだまだ学習していかないとヤバイなと思い、自分用アウトプットのためにブログ始めてみました。

更新頻度は適当にゆるい感じでやっていこうとおもてます。

これからやってみたいこと

下記をもとにスキル・キャリアアップしていけたらなぁ〜なんて思ってます!

github.com