聚會時間公告: 因應COSCUP 2011, Kalug 8月份休會一次

八月 3, 2012

Yuren's Info Area
yurinfore
is about »

tag cloud

» ReactiveUI 概念篇

ReactiveUI 解決了我兩個問題,一個是把 App 中可以測試的部分擴大,二是解決 UI/Thread 糾結的問題。

你怎麼測試你的 app 的呢?底層我們當然可以透過 unit test 的方式進行,但是通常來說 UI 上面的東西都是比較難以測試的。通常我們會透過自動化 UI 的測試如 Sikuli 測試。但是這樣自動化 UI 常常會跟畫面綁定造成常會因為畫面變更而需要重新製作測試的 script。至於 MVC 裡面 Controller 的部分常因為跟 Event 綁定造成 Controller 其實是很難以測試的。ReactiveUI 是一種 MVVM (Model View ViewModel) 的 framework,其中由 ViewModel 取代 Controller 達到連 ViewModel 這個部份都可以測試,原因在後面讓我娓娓道來。

另外,我們這邊討論的 MVVM 只限於 ReactiveUI,我並沒有用過其他的 MVVM Framework。

MVC v.s. MVVM


MVC (Model-View-Controll) 是大家現在非常常用的 pattern,基本上就是把資料 (Model)、UI (View)、邏輯 (Controller) 分開來。在 Android 或一般的 WPF 裡面,我們會把事件處理也放在 Controller 裡面,Controller 可以作為聯繫 View 與 Model 的橋梁處理各式各樣的事情。所以 Controller 處理了邏輯跟事件。那 Controller 有辦法獨立進行測試嗎?這只有在你把邏輯與事件處理拆開後才有辦法單獨針對邏輯測試。

MVVM 是有別於 MVC 的另外一種設計方式,架構如下:



你可以能會說,這架構只是把 Controller 換成 ViewModel 而已,感覺不出來什麼差別阿?但其實不是的,ViewModel 反映了 View 裡面的資料。ReactiveUI 裡面的 ViewModel 包含了兩個重要的東西:屬性與命令

我用下面這個 Mockup 舉例,這是一個可以選擇要把內容發布到不同 Social Network 的小程式,左邊的 100x100 是自己的大頭照 Avatar。右上角的輸入框是要發布的內容,下面的下拉選單是要發布到哪裡的選項。


在 View 裡面的每個需要資料的元件,指定要跟 ViewModel 裡面的哪個屬性綁定,如同上面的例子,View 裡面要指定:
  1. 圖片的 Source 位置 => AvatarSource
  2. 輸入框的文字 => ContentText
  3. 下拉式選單的選項 => SocialNetworks ["Facebook", "Twitter", "Google+"]
  4. 下拉式選單選擇的項目 => SelectedSocialNetwork
ViewModel 與 View 的互動是雙向的,比如說 (1) 我在輸入框裡面打了 "I saw The Dark Knight Rises today!",這個時候 ViewModel 裡面的 ContentText 就會更新成新的文字敘述。(2) 當我點擊下拉選單,把要發表的 Social Network 從 Facebook 改成 Twitter 後,ViewModel 裡面的 SelectedSocialNetwork 也會被修改成新的數值。從另一個方向來看,(3) 如果我在程式裡面修改了 AvatarSource 的網址,這個時候 View 裡面的圖片就會自動更新。所以兩個方向的更新都是可以的。



至於命令 (Command) 則是獨立於 View Event 的部分。在上面這個例子裡面,按下 PostButton  之後就會執行 PostCommand。由於在 Command 裡面需要的東西,如要發表到哪個 Social Network,要發表的內容都已經綁定到 ViewModel 裡面的屬性了,所以不需要跟 View 互動,只要直接取用屬性及可,我們可以用簡單的虛擬碼表示:

PostCommand.Subscribe( _ => SendToSocialNetwork (SelectedSocialNetwork, Content))

由於屬性與命令都已經 Mapping 到了 ViewModel 了。這下子 ViewModel 的部分就可以被拿出來獨立測試。如同下面的虛擬碼:

Test {
    var ViewModel = new ViewModel()
    ViewModel.SocialNetworks.AddRange("Facebook", "Twitter", "Google+")
    ViewModel.ContentText = "Test Content"
    ViewModel.PostCommand.Execute()
}

如此一來 ViewModel 就可以測試了,而且架構非常乾淨!

而 ReactiveUI 裡面包含了 ReactiveCommand 與 ReactiveAsyncCommand,當你要處理非同步事件只要用 ReactiveAsyncCommand 即可。

這樣的架構是不是很乾淨呢?下次再來講 ReactiveUI 實際上要怎麼使用。

等不及的人,這邊是 ReactiveUI 的官網

七月 6, 2012

Yuren's Info Area
yurinfore
is about »

tag cloud

» 在 Windows 透過 ssh 啟動 Linux 上 API Server 的測試方式

如果你採用 Django, Node.js 或 Rails 這些網頁開發 framework 大多都不會真的在 Windows 上架設服務,通常會在 Mac 或 Linux 架設測試伺服器。開發 Windows 的時候比較好的解決方法就是在 VirtualBox (或其他軟體) 裝 Linux 連接到上面測試。

這樣做在我的狀況下會有些問題,因為我的測試項目會更改到一些儲存在資料庫的東西會影響到下次測試的結果。所以我希望每次測試都可以用新的資料庫環境測試。今天下午花了些時間設定好,分享一下。

基本上就是透過 putty 的指令介面 plink 來執行遠端 Linux 的指令,達到開啟關閉以及清除資料庫的功能。遠端的 script 大概長這樣:

#!/bin/bash

if [ "$1" = "start" ]; then
echo "starting api service"
#start web service > /dev/null 2>&1 &
pidfile=$!
echo $pidfile > ~/api.pid
else
echo "stopping api service"
kill `cat ~/api.pid`
mongo api_db --eval "db.dropDatabase()"
fi


在 Windows 這邊可以到 putty 官網下載 plink.exe,先把它丟到家目錄去。遠端的指令要這樣執行:

%HOMEDRIVE%%HOMEPATH%\plink.exe -pw PASSWORD USERNAME@192.168.1.148 /PATH/TO/SCRIPT start

你可能注意到我沒有用 public key 的方式做,因為不知道為什麼在 linux 產生的 private key 好像沒辦法直接拿來用。後來懶得研究就直接用密碼了。

最後我們是要在 NUnit 跑的時候執行這個指令,所以你可以修改測試專案下面的 Program.cs 來達到執行指令的功能,下面我就貼出整個檔案了,基本上就是在前後加上執行的指令,ExecuteCommand 是從網路上貼來的。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Threading;

namespace YourNamespace
{
class Program
{
[STAThread]
static void Main(string[] args)
{
string script = "\\plink.exe -pw PASSWORD USERNAME@192.168.1.148 /PATH/TO/SCRIPT ";
string home = Environment.ExpandEnvironmentVariables("%HOMEDRIVE%%HOMEPATH%");
ExecuteCommandAsync(home + script + "start");
Console.WriteLine("starting service, sleep 15 seconds");
Thread.Sleep(15000);

string[] my_args = { Assembly.GetExecutingAssembly().Location };

int returnCode = NUnit.ConsoleRunner.Runner.Main(my_args);

Console.WriteLine("stopping service...");
ExecuteCommandSync(home + script + "stop");
Console.WriteLine("service stopped");
if (returnCode != 0)
Console.Beep();
}

static public void ExecuteCommandSync(object command)
{
try
{
// create the ProcessStartInfo using "cmd" as the program to be run,
// and "/c " as the parameters.
// Incidentally, /c tells cmd that we want it to execute the command that follows,
// and then exit.
System.Diagnostics.ProcessStartInfo procStartInfo =
new System.Diagnostics.ProcessStartInfo("cmd", "/c " + command);

procStartInfo.RedirectStandardOutput = true;
procStartInfo.UseShellExecute = false;
// Do not create the black window.
procStartInfo.CreateNoWindow = true;
// Now we create a process, assign its ProcessStartInfo and start it
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo = procStartInfo;
proc.Start();
// Get the output into a string
string result = proc.StandardOutput.ReadToEnd();
// Display the command output.
Console.WriteLine(result);
}
catch (Exception objException)
{
// Log the exception
}
}

static public void ExecuteCommandAsync(string command)
{
try
{
//Asynchronously start the Thread to process the Execute command request.
Thread objThread = new Thread(new ParameterizedThreadStart(ExecuteCommandSync));
//Make the thread as background thread.
objThread.IsBackground = true;
//Set the Priority of the thread.
objThread.Priority = ThreadPriority.AboveNormal;
//Start the thread.
objThread.Start(command);
}
catch (ThreadStartException objException)
{
// Log the exception
}
catch (ThreadAbortException objException)
{
// Log the exception
}
catch (Exception objException)
{
// Log the exception
}
}
}
}

七月 2, 2012

Yuren's Info Area
yurinfore
is about »

tag cloud

» Jenkins, NUnit and VS 2010 express!

好吧你沒看錯主題,我要講的真的是 Visual C# 2012 express。

當要開始開發程式的時候,最重要的就是基礎架構先弄好之後開始,在 Windows application development 也一樣,但是跟其他平台開發有個不太小的不同,Windows 的開發軟體都是要錢的,所以你想要的功能基本上獨立開發者是無法負擔的。你還在想念 Android, Java, Linux, Mac app 開發一些基礎的東西嗎?像是 Code Coverage, Source Control (TFS), Lint (Static Code Analysis)在 Visual Studio 都是要錢的。

當然我們這種從 Android/Linux development 轉過來的人,當然是希望用 Open Source 的 solution。首先就從最基本的 Continues Integration 跟 unit test 講起。

請先安裝好 Visual C# 2010 express,Jenkins, Java runtime。

CI 當然就是選 jenkins 了,至於要搭配的東西就比較麻煩。在這邊我們採用 msbuild 建構專案,使用 NUnit 作 unit test。因為我們要在 Windows 上 build,所以 Jenkins 也要安裝在 Windows 上面。基本上就是從 jenkins 上面抓下來,找個風水好地放著,執行 java -jar jenkins.war 就行了。

接下來安裝 msbuild, nunit 這兩個 plugins。接下來就到 jenkins → Manage Jenkins → MSBuild 裡面填寫 MSBuild 正確的位置。


第二個是建立 NUnit 專案,你可以在 VC# 裡面 Tools → Extension Manager → Online Gallery → NUnit Test Application 安裝 NUnit 的 project template,怎麼寫 test case 就上網找一下吧。

當你建立專案的時候,他會很佛心的幫你建一個執行檔組態。執行他就可以獲得 NUnit Test report。

最後是 Jenkins job 的設定。在我們還沒有使用任何 Version Control 的時候,我們可以先從 VS project 裡面複製出專案的方式先代替 Clone project。


首先需要先清除 workspace 裡面遺留下來上次 build 過的東西。因為 Windows 刪除檔案跟目錄太囉嗦了,我這邊用 PowerShell 的指令代替。第二行則是用 xcopy 用複製的方式先把專案複製到定位。



第一個動作是用 MSBuild 去 build solution,這個 solution 包含了兩個 project,一個是主要的專案,另外一個是用來測試的專案。第二個動作則是跑由 NUnit project template 幫我們產生的 Test 執行檔,執行後就可以產生 TestResult.xml,第三個步驟就是引用這個檔案,讓 Jenkins 產生正確的報告在 Jenkins 的頁面上。

這樣就基本的把 Jenkins 設定好了。

七月 30, 2010

小惡魔AppleBOY
AppleBOY
is about »

tag cloud

» [網站] 好站連結 (七) Android, javascript, Css, PHP, Perl, FreeBSD, Linux

Windows C# C# 比較字串 MSDN 比較字串 Request.Form Collection Request Query String / Form Parametrs ...詳全文(共1347字)

support:

biggo.com.tw

biggo.sg

A Django site.