SalesForce開発のTips(備忘録)
SalesForce Apexのテストの備忘録
コードカバー率の調査
開発者コンソールの [Query Editor]タブで[Use Tooling API] をチェックして、下記A or Bを実行

- 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を実行してみた

ソースはこちら
github.com
環境・言語
- OS
- macOS Mojave 10.14.5
- 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 に登録
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 にプロジェクト追加


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




まとめ
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 installとnpm run build(webpack)を実行する処理をbuild.gradleに実装し、毎ビルド時にbuilde.gradleが読み込まれるように設定してみた。
環境・言語
- IDE
- intelliJ idea 2018.3.4
- backend-framework
- Spring boot 2
- backend-language
- kotlin
- frontend-framework
- vue.js
- frontend-language
- html
- css
- javascript
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_modulesやpackage-lock.jsonが生成されました。
まとめ
vue.js側を更新した際にいちいち npm run build を実行しなければならないところをrunのみで、 全てbuildされて動作確認できるようになりました。