2016年3月7日 星期一

【SQL】PIVOT 讓搜尋結果橫式表現


有時候SQL搜尋出來的資料是直式的,但偏偏PM們常常想看的卻是橫式報表,狀況模擬如下

DECLARE @Report TABLE (
CompanyName varchar(8),
[Year] int,
[Month] int,
Revenue int)

insert @Report values('A公司',2016,1,100)
insert @Report values('A公司',2016,2,100)
insert @Report values('A公司',2016,3,100)

insert @Report values('B公司',2016,1,200)
insert @Report values('B公司',2016,2,200)
insert @Report values('B公司',2016,3,200)

insert @Report values('總公司',2016,1,300)
insert @Report values('總公司',2016,2,300)
insert @Report values('總公司',2016,3,300)

select * from @Report

這是資料在資料庫裡面的記錄方式

PM想看到的


還好MS SQL 2005之後提供PIVOT來解決這種問題,實際SQL如下


select 
[date] as '年/月份',
[A公司] as 'A公司' ,[B公司] as 'B公司' ,([A公司] + [B公司] + [總公司]) as '總公司'
from(
 select
 CompanyName,
 cast([Year] as char(4)) + '/' + cast([Month] as char(2)) as [date],
 Revenue
 from @Report
 group by CompanyName,[Year],[Month],Revenue
) as TempReportTable
PIVOT
(
 sum(Revenue)
 for CompanyName in ([A公司] ,[B公司] ,[總公司])
)as PivotTable

算出結果

2016年3月6日 星期日

【Unit Test】重構 (二) 單元測試的可讀性


  1. 方法命名  :  受測的方法名稱Test_動作_預期結果

    這樣可以看標題名稱,馬上就能大略的明白此單元測試的受測者與目標是什麼,對於之後如果改版發生單元錯誤時,也才能明白該如何修復
    錯誤寫法 

     哪天因為改版造成這個單元測試錯誤了,要修復時非得看完全部的Code才能明白何謂"正確的狀況",對於維護來說是不利的

    建議寫法



  2. 共用的參數應該有個父類別來管理
    有時候我們會為了測試某些情境,對於public static的東西進行設定,但也因為這是public static的變數,為了避免與其它單元測試交互影響,所以我們會在TestCleanUp的方法中做清除的動作



    但這種寫法如果散落在各個單元測試的Class之中,對於維護也是一大挑戰,所以建議建立一個TestBase之類的父類別,讓所有單元測試的類別繼承它,並統一管理。

總結,單元測試是為了讓程式更有品質,且在一些保護的基礎上進行改版,但如果單元測試的撰寫沒有一些有效的管理,對於後續的維護成本可能會比沒單元測試來的更高更難維護,如果單元測試寫的不清不楚,誰會知道這個測試到底要保護什麼呢?

2016年3月1日 星期二

【Unit Test】重構 (一) 透過繼承解耦


將一個本來沒有單元測試的專案,改成能測試的狀態,通常第一個遇到的問題就是耦合太深,導致無法切開來模擬外部對象,大幅度改動又可能牽扯很多Method與Class,在沒有測試保護下,怕改到壞掉而不自知。

以下記錄第一種重構方式,讓測試能在安全的重構之下進行

範例Code:
原本的Legacy Code 
    public class UnitTestSampleBase
    {
        public UnitTestSampleBase() { }



        public int WantUnitTestMethod()
        {
            //直接引用,導致無法隔離測試
            ThirdPartyObject tpObj = new ThirdPartyObject();

            int value =  tpObj.GetValue();

            return value + 1;
        }
    }


  1. 分離耦合的部分

     public class UnitTestSampleBase
        {
            public UnitTestSampleBase() { }
    
            protected virtual int GetValue()
            {
                //開一個virtual的Method,將外部引用隔離出來
                ThirdPartyObject tpobj = new ThirdPartyObject();
                return tpobj.GetValue();
            }
    
            public int WantUnitTestMethod()
            {
                //避免直接引用
                int value = GetValue();
    
                return value + 1;
            }
        }
    


  2. 做一個Fake的受測對象,並繼承受測得目標,並改寫取得外部資源的結果的Method,讓它回傳我們寫死的固定值
    public class UnitTestSampleFake : UnitTestSampleBase
        {
            protected override int GetValue()
            {
                return 1;
            }
        }
    


  3. 進行測試
    [TestClass]
        public class UnitTestSampleFakeTest
        {
            [TestMethod]
            public void WantUnitTestMethod_Call_ShouldRetuen2()
            {
                //arrange
                var sut = new UnitTestSampleFake();
                //act
                var actual = sut.WantUnitTestMethod();
                //assert
                //1+1 = 2
                Assert.AreEqual(actual, 2);
            }
        }
    
  4. 測試通過


這樣對於外部使用你的Mthod的人來說,他Code都不用改(因為你還是保有原本的Method
WantUnitTestMethod,且不需要額外的外部注入或參數注入),但你的Code已經做了初步的分離跟測試,之後就可以慢慢在這個測試保護的基礎之上,繼續後續的開發了!!