2013年3月2日 星期六

[書摘]《用戶故事與敏捷方法》第6章 用戶故事與驗收測試

 

小結


1. 驗收測試可以用來記錄客戶和開發人員討論的很多細節。

2. 驗收測試紀錄了有關故事的一些假設,這些假設可能還沒有和開發人員討論過。

3. 驗收測試提供了檢查故事是否被完整實現的基本標準。

4. 驗收測試應由客戶來血而不是開發人員。

5. 驗收測試應在程序員寫代碼之前就寫好。

6. 如果新的測試對闡明故事的細節或意圖沒有任何幫助,就不用再寫。

7. FIT和FitNesse是寫驗收測試的優秀工具,他們用的是我們熟悉的表格或電子表格格式。

開發人員職責


1. 若團隊覺得有需要,則負責實現自動化驗收測試。

2. 開始開發一個新的故事時,負責考慮更多的驗收測試。

3. 負責為代碼做單元測試,使驗收測試就不必顧及故事的每個細節。

客戶職責


1. 負責編寫驗收測試

2. 負責執行驗收測試

2012年7月1日 星期日

[Rx]使用LinqPad 4來測試Reactive Extension

  1. 先到 LinqPad官網 下載 LinqPad。需要第4版以上才有支援Rx。
  2. 下載 Reactive Extensions (Rx) v2.0 Release Candidate 。
  3. 設定LinqPad的Query Properties:[Query]=>[Query Properties]或按F4來設定。設定需要依據Assembly的結構,如下圖:

               image

              image

             image

  4. 右邊可以使用C# Statement(s)來做運算。

             image

  5. 也可以選擇C# Program來運算。

                  image

參考資料:

2012年6月14日 星期四

使用Expression Encoder進行影片轉檔

測試的程式碼如下,這邊是轉出為WMV的VC-1格式,
如果要轉檔成MP4的格式,需要使用"Expression Encoder 4 Pro (with codecs)"授權版本,不然會出現錯誤訊息。
image
using System;
using Microsoft.Expression.Encoder;
using Microsoft.Expression.Encoder.Profiles;

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
MediaItem mediaItem = new MediaItem(@"C:\Temp\24.wmv");

//mediaItem.OutputFormat = new MP4OutputFormat();
WindowsMediaOutputFormat wmof = new WindowsMediaOutputFormat();
wmof.VideoProfile = new MainVC1VideoProfile();
wmof.AudioProfile = new WmaAudioProfile();
mediaItem.OutputFormat = wmof;

//Creates job and media item for the video to be encoded
Job job = new Job();
job.MediaItems.Add(mediaItem);

//Sets output directory
job.OutputDirectory = @"C:\Temp\converted";

//job.DefaultMediaOutputFileName = "24.mp4";
job.DefaultMediaOutputFileName = "24.wmv";

//Sets up progress callback function
job.EncodeProgress += new EventHandler<EncodeProgressEventArgs>(OnProgress);

//Encodes
Console.WriteLine("Encoding…");
job.Encode();
Console.WriteLine("\nFinished encoding.");
job.Dispose();

Console.ReadKey();
}

static void OnProgress(object sender, EncodeProgressEventArgs e)
{
Console.Write("\b\b\b\b\b\b\b");
Console.Write("{0:F2}%", e.Progress);
}

}
}
參考資料:


  • C:\Program Files (x86)\Microsoft Expression\Encoder 4\SDK

  • C:\Program Files (x86)\Microsoft Expression\Encoder 4\zh-Hant\Encoder.chm

2012年6月13日 星期三

關於C#裡 System.DBNull.Value & Convert.IsDBNull 的迷思

繼續自話題關於C#裡 System.DBNull.Value & Convert.IsDBNull 的迷思:

原貼為:

想請教一下, 在C# 裡, 我要判斷資料表欄位是否為 Null 值, 是要用

if (DataTable.Rows[0][0] == System.DBNull.Value)

{

}

還是要用

if (Convert.IsDBNull(DataTable.Rows[0][0]))

{

}

那一個來做比較好? 為什麼?

正確的答案是:

Convert.IsDBNull 比較好。

為什麼?

DataTable.Rows[0][0] 傳回來的值,或說取自資料庫的值,傳回的型別大都是Object,必須要先利用轉型才可以正確判斷。

使用 if (DataTable.Rows[0][0] == System.DBNull.Value) 大都是False,微軟不會沒事找事做,微軟的東西也會經過一定的測試流程才發佈出來,

盡量使用可靠的東西準沒錯。

備註:

我遇到的錯誤情況是

if (tr["Tradition"] != DBNull.Value) btrTradition.ReportComplete = Convert.ToDateTime(tr["Tradition"]);
參考資料:

2012年6月5日 星期二

[WP7]Live Tile偵錯

在WMAppManifest.xml的原有<Tasks>加上程式碼,如下:

<Tasks>
  <
DefaultTask  Name ="_default" NavigationPage="View/LoginPage.xaml"/>
  <!--
For Live Tile Debug Start-->
  <
ExtendedTask Name="BackgroundTask">
    <
BackgroundServiceAgent Specifier="ScheduledTaskAgent" Name="ScheduledTaskAgent1"
                           
Source="DummyAgent" Type="DummyAgent.ScheduledAgent" />
  </
ExtendedTask>
  <!--
For Live Tile Debug End-->
</
Tasks>

在Release正式版之前,記得拿掉這個區段。

參考資料:

2012年5月26日 星期六

WebClient和HttpWebRequest的不同

WebClient 是 HttpWebRequest 類相關的包裝類,用於執行 Web 服務請求。WebClient 更易於使用,因為它會將結果數據返回到應用程序的 UI 線程,因此應用程序不需要將數據封送到 UI 線程。但是,如果應用程序處理 UI 線程上的 Web 服務數據,則 UI 將直到處理完成才做出響應,這樣就會導致很差的用戶體驗,尤其是要處理的數據集過大時。

使用 HttpWebRequest 代替 WebClient
使用 HttpWebRequest 發出 Web 服務請求。處理異步請求線程上的結果數據,然後使用 BeginInvoke 將數據封送到 UI 線程。

另外,HttpWebRequest可以針對環境和Cookie來做特定的設置,這是使用WebClient所沒有辦法做到的。

參考資源:

2012年5月13日 星期日

[SVN]將已簽入SVN的變更集重新打包為資料夾

可以很方便的對客製的同一工作項目進行覆蓋式的修改。

因為不是每一個客戶都有SVN的Patch可用,也不適合對不透明的系統使用SVN的Patch指令。

 

限制:

這裡只有做新增的部分,保留刪除與修改功能,有需要的人也可以依據自己的工作來最對應的修改。

需要安裝SVN客戶端 – TortoiseSVN

只適用於台灣地區,其他地區可能在顯示上會有亂碼,但不影響功能。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Reflection;
using System.IO;
using System.Xml.Linq;
namespace SvnPkg
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args.Length < 3)
            {
                Console.WriteLine("snvlog: 將指定的SVN變更集整理到指定的目錄下。");
                Console.WriteLine("用法:svnpkg [專案根目錄] [輸出目錄] [版本變更集]");
                Console.WriteLine(@"例如:svnlog D:\SVN\XXXXXX D:\Temp 228,230:231");
                return;
            }
            String SvnPath = @"C:\Program Files\TortoiseSVN\bin\svn.exe";
            String ProjectPathArg = args[0];
            String OutputPathArg = args[1];
            String ChangesetArg = args[2];
            if (!File.Exists(SvnPath))
            {
                Console.WriteLine("找不到svn:" + SvnPath);
            }
            //解析revision
            List<int> Changesets = new List<int>();
            foreach (String sub in ChangesetArg.Split(','))
            {
                if (sub.Contains(':'))
                {
                    int start = Convert.ToInt32(sub.Split(':')[0]);
                    int end = Convert.ToInt32(sub.Split(':')[1]);
                    for (int i = start; i <= end; i++)
                    {
                        if (!Changesets.Contains(i))
                        {
                            Changesets.Add(i);
                        }
                    }
                }
                else
                {
                    if (!Changesets.Contains(Convert.ToInt32(sub)))
                    {
                        Changesets.Add(Convert.ToInt32(sub));
                    }
                }
            }
            //依據變更集的先後順序排列
            Changesets.Sort();
            //Console.WriteLine(args[0]);
            Process svnProcess = new Process();
            svnProcess.StartInfo.FileName = SvnPath;
            svnProcess.StartInfo.CreateNoWindow = true;
            svnProcess.StartInfo.UseShellExecute = false;
            svnProcess.StartInfo.StandardErrorEncoding = Encoding.UTF8;
            svnProcess.StartInfo.StandardOutputEncoding = Encoding.UTF8;
            svnProcess.StartInfo.RedirectStandardError = true;
            svnProcess.StartInfo.RedirectStandardInput = true;
            svnProcess.StartInfo.RedirectStandardOutput = true;
            XDocument doc;
            foreach (int cs in Changesets)
            {
                svnProcess.StartInfo.Arguments = "log " + ProjectPathArg + " -v -r " + cs.ToString() + " --xml";
                svnProcess.Start();
                doc = XDocument.Load(svnProcess.StandardOutput);
                //String revision = doc.Document.Descendants("logentry").First().Attribute("revision").Value;
                //String msg = doc.Document.Descendants("msg").First().Value;
                //String date = doc.Document.Descendants("date").First().Value;
                //Console.WriteLine("revision:" + revision + " " + msg);                
                foreach (XElement elem in doc.Document.Descendants("path"))
                {
                    String basePath = elem.Value.Replace('/', '\\');
                    if (basePath.StartsWith("\\"))
                    {
                        basePath = basePath.Substring(1);
                    }
                    if (elem.Attribute("kind").Value == "file")
                    {
                        switch (elem.Attribute("action").Value)
                        {
                            case "A": //Add
                            case "M":  //Modify
                                String srcFile = Path.Combine(ProjectPathArg, basePath);
                                String descFile = Path.Combine(OutputPathArg, basePath);
                                String descDir = descFile.Substring(0, descFile.LastIndexOf('\\'));
                                
                                if (!Directory.Exists(descDir))
                                {
                                    Directory.CreateDirectory(descDir);
                                }
                                File.Copy(srcFile, descFile,true);
                                break;
                            default:
                                Console.WriteLine("未處理的動作:" + elem.Attribute("action").Value);
                                break;
                        }                        
                    }
                    else if (elem.Attribute("kind").Value == "dir")
                    {
                        ;
                    }
                    else
                    {
                        Console.WriteLine("未處理的種類:" + elem.Attribute("kind").Value);
                    }
                }
                //顯示目前處理的revision(使用big5才不會有亂碼)
                svnProcess.StartInfo.Arguments = "log " + ProjectPathArg + " -v -r " + cs.ToString();
                svnProcess.StartInfo.StandardOutputEncoding = Encoding.GetEncoding("big5");
                svnProcess.Start();
                Console.WriteLine(svnProcess.StandardOutput.ReadToEnd());
                //回覆解析XML需要使用的UTF8編碼
                svnProcess.StartInfo.StandardOutputEncoding = Encoding.UTF8;
            }
            Console.WriteLine("Done!");
        }
    }
}