コード書くときのこのエディタの使い方が
docker compose up -d
わかるけど。ちょっと面倒だな。
コード書くときのこのエディタの使い方が
docker compose up -d
わかるけど。ちょっと面倒だな。
ろくでなしブルースもう一回読みたいな。高校1年のときめっちゃ教室で読んでたな。そしてえいちゃんの白い下敷き懐かしい。
今日はちょっとSharePointブログについて調べてみましょうかね。何かを調べながら試して、ノウハウを残すという行為をいっぱいするようになったのだけど、これをきっちりアウトプットする先がほしい。自社の社内ブログ標準のWordpressがサーバが弱すぎるのか遅すぎて、もうちょっとどうにかなってほしいのだが。いっそ外部のnoteとかQiitaを主戦場にしてみるかどうか。Sphinxをブログ風に使うような拡張機能もあるならそれもありだけども。
あとClaudeの件もちゃんと調べないとだし、昨日開発したSimpleRAGを自社のとこに置いてしまうハックもやりたいなー。
と言う前にゼロタッチのノウハウまとめをやらなければ。3月に全体脱稿をまず目指すか。やりたいことたくさんだなあ。
自宅で運用しているサーバの作りを、結構大きく見直した。ハードウェアは何も変わっていないけど。
まず、VMWare ESXiをやめた。それの上に色んなサーバ立てるのも楽しかったのだけど、1サーバごとにCPUコアの使用制限がかかっているのがどうも気になっていたので一度外してみることにした。KVMとか代替手段もあるようなので。いったんハイパーバイザ的なことはやめてUbuntuをクリーンに入れてみた。
しかし、それが簡単にはいかなくて、何が厳しいかというとPCIスロットにカード増設してインストールしたNVMe SSDにOSを入れてやろうとしたものの、どうもこの人はUEFIブートの出発点にできないらしく、LinuxをUSBメモリからそのドライブにインストールすることもできるのだが、起動画面でずっと空振りするようなことになってしまう。
Clover EFIという救世主らしきものに出会ったけど、これもダメで結局SATA HDDにインストールした。ここまででどえらい時間が溶けた。
そして、色んなアプリをインストールしていくのだが、すべてDocker ComposeでやってホストOSはできるだけ何もない状態に、というのを目指してみる。Dockerでやると、Composeファイルとかを全部Gitで管理して、設定ファイルも同じところにおいてVolumeとしてマウントしてあげることで環境がまっさらになっても結構楽ちんで同じものが作れる。データの永続化もHDDにしてから多重化しておくと安心。
これはこれで結構苦労しているけど、現状動かせているアプリケーションやサービスは以下。
この後もうちょっとやりたいのもある。
Mkdocsも手足のように使いこなせるようになっときたいなー。
さっほんっ
なんでもいいので、お弁当配達サービス。
サービスの単価を設定。朝食とお弁当で300食。単価500円。週6。25 × 150,000で月間売上3,750,000円。
3人は必要で人件費60万円。
原価140万円。
光熱費など10万円。
税金。
広告、配達、パート。
調理場借りるの15万
減価償却費20万円。
なんだか利益出せるかな、くらい。
やってみたが断念したもの
Cakephp 4で作ったアプリにバッチ処理も作り足したい場合はコンソールコマンドを使うことになるが、その使用例はこうなっている
$ bin/cake hello
自分が作業していた環境(RHEL)は、phpのバージョンが7.4と8.2がどちらもインストールされており、どちらも使っている。今回8.2で実行したいが、単純にシェルでphpコマンドを打つと今は7.4が有効なので
$ bin/cake
PHP Fatal error: Your PHP version must be equal or higher than 7.4.x to use CakePHP. in /var/www/html/xxxxx/config/requirements.php on line 24
という感じでエラーが出る。そりゃそうだよね。
Webとかでもあまりはっきり書いてないけど、これで解決する。
$ php82 ./bin/cake.php
No command provided. Choose one of the available commands.
Current Paths:
* app: src/
* root: /var/www/html/xxxxx/
* core: /var/www/html/xxxxx/vendor/cakephp/cakephp/
Available Commands:
App:
- help
Bake:
- bake
- bake all
- bake behavior
- bake cell
- bake command
- bake command_helper
- bake component
- bake controller
- bake controller all
- bake fixture
- bake fixture all
- bake form
- bake helper
- bake mailer
- bake middleware
- bake model
- bake model all
- bake plugin
- bake shell_helper
- bake template
- bake template all
- bake test
Cake/TwigView:
- twig-view compile
CakePHP:
- cache clear
- cache clear_all
- cache list
- completion
- i18n
- i18n extract
- i18n init
- plugin assets copy
- plugin assets remove
- plugin assets symlink
- plugin load
- plugin loaded
- plugin unload
- routes
- routes check
- routes generate
- schema_cache build
- schema_cache clear
- server
- version
DebugKit:
- benchmark
Migrations:
- bake migration
- bake migration_diff
- bake migration_snapshot
- bake seed
- bake simple_migration
- migrations
- migrations create
- migrations dump
- migrations mark_migrated
- migrations migrate
- migrations orm-cache-build
- migrations orm-cache-clear
- migrations rollback
- migrations seed
- migrations status
To run a command, type `cake command_name [args|options]`
To get help on a specific command, type `cake command_name --help`
Python Djangoを使ってWebアプリを作り始めて、今まで自動テストをちゃんとやったことがなかったので、いい加減にこの機会にちゃんと学ぼうと思って、30-40時間を学習と試行に費やしたけど結局諦めたという話。
テスト駆動開発くらいの言葉もあるし、Qiitaにはこんな素晴らしい投稿をされている人もいて概念自体はとてもいいなと思うものの、作業量があまりにも多すぎる。感覚的には、動くアプリを書いて画面をチェックして開発を進めるだけっていうのの3倍以上の時間がかかる気がする。PythonやDjangoでなくてもなんだって同じだろうなという気がする。
CI/CDなんて概念も、もはや世の中では当たり前だよというような感じで語られているし、自分は、とにかく回帰テストとしてDjangoのテストフレームワークを使いたかった。関数ベースビューが何十にもなって、モデルの数もどんどん増えていき、何か新機能を付けたりバグを修正したりした時に、既存のうまくいっているところが動かなくなるのを防ぐのには確かにうってつけなので。
改修する、それがうまくいっているかテストする、そのテストをWebブラウザを操作して目検で確認するだけでなくコード化する、蓄積されたテストをすべてブン回して何もかもうまくいくことを確認して、本番環境にリリースする。ということが毎回できればよいなというお話です。
Django付属のTestCaseから試したが、まずこのテストは大きく二つの目的に使える。
その1はモデルのテスト、その2は疑似ブラウザ(Client)を使った画面動作のテスト。
モデルのテストはこんな塩梅になる。
class CompanyModelTests(TestCase):
def setUp(self):
self.cp = Company(
name="test company",
since=timezone.now(),
start_year='same',
start_month=4,
)
self.cp.save()
return super().setUp()
def test_cp_count(self):
cp = Company.objects.all().first()
self.assertEqual(len(Company.objects.all()), 1)
Companyというモデルを1件Saveしてあげて、テストメソッド(test_cp_count)にて、Companyのモデルの数を数えてあげたらちゃんと1になるよね、というテストコードになる。Webのチュートリアルとかを見ても、これくらいのサンプルコードは山ほどあるので、理解はしやすい。
しかし、こんなテストを大量に作ってどこまで意味があるのかと、この作業を延々続けることがばかばかしく思えてしまう。この例はほぼDjangoのフレームワークをテストしているだけだ。じゃあ、Modelに自分で追加したメソッドをテストすればいいということにはそれは賛成なのだけど、結局そんなメソッド単体でテストしたところで、基本はViewのロジックがテストされないと意味ないし、Viewが期待通り動いてくれてるかどうかを見るのが大事なのに、部品のテストにそこまで時間をかけるのが正解かどうか。だいぶ包含されるし。
そして、Viewをテストするとなると、その2.疑似ブラウザ的なClientを利用したテストになる。これはだいぶいいものに思えた。
class CompanyDisplayTests(TestCase):
fixtures = ['test_data_01']
def setUp(self):
self.p_ad = Person.objects.filter(pk=2).first()
self.client.force_login(self.p_ad.user)
return super().setUp()
def test_company_top_suc(self):
''' company top normal show'''
response = self.client.get('/pj01/company_top')
self.assertContains(response, "Project and Workcodes")
self.assertEquals(response.status_code, 200)
def test_wctype_change_order(self):
''' wctype_change_order '''
self.client.force_login(self.p_ad.user)
data = {"form-0-id": "1",
"form-0-cp": "1",
"form-0-name": "Normal",
"form-0-is_active": "on",
"form-0-ord": "03",
"form-1-id": "2",
"form-1-cp": "1",
"form-1-name": "AO",
"form-1-is_active": "on",
"form-1-ord": "20",
"form-TOTAL_FORMS": "2",
"form-INITIAL_FORMS": "1",
"form-MIN_NUM_FORMS": "0",
"form-MAX_NUM_FORMS": "20",
"modify": "Save"}
response = self.client.post('/pj01/mt_wctype', data)
response = self.client.get('/pj01/mt_wctype')
self.assertContains(response, 'Succesfully Saved.')
self.assertEquals(response.status_code, 200)
DjangoのTestCaseでは、self.clientという疑似ブラウザが使える。この例では、’/pj01/company_top’というURLをGETリクエストして、その結果返ってきたHTMLに入っている文字列と、レスポンスのHTTPステータスコードが200であることを検証して、いずれかに問題があればテストがエラーとなる。
同様に、画面に対するPOSTをすることも可能。それが上記サンプルの中のtest_wctype_change_order。postメソッドで呼んで配列を渡してやることでWebブラウザからのデータ入力、そのあとのメッセージの検証や、例からは省略したがModelを使ってDBにデータが想定通り格納されたかを検証させることもできる。
fixtureというDBの基本マスターデータをロードして、毎回まっさらなデータベースを用意してくれる思想もなるほどなと思った。前回のテスト実行の結果でデータが変わっていたら同じ結果が得られないという悩みはない。
そして、こんなコードを手でいちいち書いてトライアンドエラーするのもまた時間がもったいないので、コードを書いたあとに手動でブラウザを動作させてテストしてあげるときにうまくログを吐き出させて、上記のようなテストコードへ流用する情報、主にURLやPOSTデータをTextファイルに吐き出すようにMiddlewareを作ってやることによってテストコードを作る手間を省力化させてもみた。
しかしそれでも、画面でテストした通りのことを、こいつにサクッとやらせるまでにはどうしても至らなかった。
いくつか問題があって
Webで色々調べたけれど、どれもいい解決策に至らず、僕ちゃんにはCI/CDなんてまだ早かったのかな、落ちこぼれだな、と泣いた。何をどうやって見ても、回帰テストが1コマンドでブン回せるというメリットに釣り合うとはとても思えないほどの労力がかかると思われた。
Djangoのtestcase.clientはそれでもどうしても使いこなしたかったので粘った。Seleniumを使ったLiveServerTestCaseも存在は知っていたけど、こちらは気軽にテストが回せないのが気にかかった。本当のWebブラウザをスクリプト操作でテストさせる場合、完全に直列でテストが走るから、テストコードが蓄積するほどに待ち時間が長くなるのが必至。テストコード自体のテストみたいなのが発生するの明白だから、1回あたりの実行時間が長くなるのはどうも気が進まなかった。
でもそれでも、本当にやりたいことは
・VsCodeでアプリを書いて
・横でブラウザでそれを叩いてみて期待通り動作するかを見る
・うまく動いていれば開発を続ける、期待と違ったら修正して再度見る
・一通りうまくいったことを確認したら、ブラウザで確認した手動テストを自動テストコード化して回帰テストとして蓄積する
ということなので、Seleniumにも行ってみることにした
やりたかったことは
①VsCodeでアプリを書き、manage.py runserverしたテスト環境で叩いて機能を作っていき
②大体満足したところで、Selenium IDEを起動、開発したコードが一通り叩けるような操作をレコード
③それをやる過程で、Selenium IDEのスクリプトの中にAssertを仕込んでいく
④PythonコードをExportする
⑤DjangoのLiveServerTestCaseを継承したテストクラスにスクリプトとして取り込む
⑥テストコードがうまく動くことを確認したら、テストコードとして蓄積していく
という流れ。
②と③は大まかにはうまくいったけど、Assertに関してはHTTPのステータスコードを取得する機能はないことが判明。公式にも、それをやろうとしていること自体が間違ってるよ的な見解が。あれば楽なのになと思ったけど、<h1>タグとかみればええやん、って書いてある。
それではとあきらめてAssert Textを多用していくが、、、全文一致しかAssertが通らず部分一致やる方法がどうもなさそうだ。これもつらい。
Pythonコードを出力した後、LiveServerTestCaseにはめ込んだら一応動いているような気もするが
TypeError: expected str, bytes or os.PathLike object, not NoneType
動作はしているっぽいけど吐き出し続けられる謎のこのエラーは一体何なのか。ググっても何もわからない。
さらに動いている画面を見るとCSSとかが読み込めておらず何とも調子が出ない。これも直し方あるのかな。
CI/CDとか自動テストがこんなに大変なものなのかと愕然とし、いったん使うのをあきらめることにした。Djangoとして機能がすでに十分そろっていて、自分の頭が足りなくて使いこなせていないだけなのか、世の中の皆さんは大変な労力をかけてちゃんとやっていらっしゃるのか、本当はまだ全然普及してなくてマニュアルテストが大半の世の中なのか、謎。
自動テストは、回帰テストでGetした画面が想定外のステータスコード返してきてないかくらいをチェックするくらいにとどめて、マニュアルテスト基本でやっていくことにする。
フォートナイトをチャプター3シーズン5は一切プレイしないことにする。うちのお兄ちゃんも受験だしちょうどいい。人を銃で撃って、よっしゃああとか言ってるのも野蛮だし。やらないって決めたら決めたで特に寂しくもない。
小学校の個人懇談いった。先生と大体認識一致。落ち着きがないのよね。
冷凍のシーフードミックスと、トマトとナスとしめじと人参とピーマン、塩とオリーブオイルと鷹の爪にニンニクとショウガ入れて適当に今煮ている。おいしいかなこれ。
Windows 11になってもこの画面ちゃんと残ってるの心温まる。