Wednesday, January 30, 2008

short introduction of c# syntax

Keywords: C#, Syntax


i sometimes forget some c# basic. There are some links which can help me keep in mind.


Sharp New Language: C# Offers the Power of C++ and Simplicity of Visual Basic


http://msdn.microsoft.com/msdnmag/issues/0900/csharp/default.aspx


C++ -> C#: What You Need to Know to Move from C++ to C#


http://msdn.microsoft.com/msdnmag/issues/01/07/ctocsharp/


Nice Things About C#


http://www.cs.princeton.edu/~cdecoro/csharp.html

Tuesday, January 29, 2008

Download Web Content other than using WebClient class

Keywords: WebClient, UTF-8, WebRequest


从一个URI上下载网页Content或Xml, 可以直接使用WebClient类(在System.Net命名空间), 非常简单. 它有很多Download方法, 比如DownloadString()和DownloadFile(). 这些都是同步方法, 当然它也有异步Download方法, 不过经常用的是它的同步方法.


但在用WebClient.DownloadString()一个以UTF-8编码格式存盘的一个Xml文件时, 得到的Xml字符串有乱码, 不管怎样设置WebClient的Encode属性都没有用处, 可能是WebClient的一个bug吧.


可以WebRequest方法来实现同步DownloadString的功能. 代码如下:




public void DownloadAndLoadXml(string uri, XmlDocument doc)
{
System.Net.WebRequest request = System.Net.WebRequest.Create(uri);
using (System.Net.WebResponse response=request.GetResponse())
using (System.IO.Stream stream=response.GetResponseStream())
{
if (stream.Length > 0)
{
stream.Position = 0;
doc.Load(stream);
}
}
}



/// <summary>
/// download the web page from the given uri
/// </summary>
/// <param name="uri"></param>
/// <returns></returns>
public string DownloadStringFromWeb(string uri)
{
System.Net.WebRequest request = System.Net.WebRequest.Create(uri);
using (System.Net.WebResponse response = request.GetResponse())
using (System.IO.Stream stream = response.GetResponseStream())
{
System.IO.StreamReader reader = new StreamReader(stream);
//save all info from stream into a string variable
string result=reader.ReadToEnd();
reader.Close();
return result;
}
}

Monday, January 28, 2008

the progress for advance listening english program in kekenet


Keywords: Linsten practice



黑体字部分为听完的节目.



http://www.kekenet.com/Article/jinjie/Index.shtml



· 进阶听说 Lesson12 (alex,01-12)


· 进阶听说 Lesson11 (alex,01-12)


· 进阶听说 Lesson10 (alex,01-12)


· 进阶听说 Lesson9 (alex,01-12)


· 进阶听说 Lesson8 (alex,01-12)


· 进阶听说 Lesson7 (alex,01-12)


· 进阶听说 Lesson6 (alex,01-12)


· 进阶听说 Lesson5 (alex,01-12)


· 进阶听说 Lesson4 (alex,01-12)


· 进阶听说 Lesson3 (alex,01-12)


· 进阶听说 Lesson2 (alex,01-12)


· 进阶听说 Lesson1 (alex,01-12)


Boy meets world(淘小子看世界)进度

Keywords: English Learning


黑体字部分为看过的视频.


Boy Meets World




【TV】 2007-12-07, 《淘小子看世界》 Breaking Up - 9


【TV】 2007-12-05, 《淘小子看世界》 Breaking Up - 8


【TV】 2007-12-03, 《淘小子看世界》 Breaking Up - 7


【TV】 2007-11-30, 《淘小子看世界》 Breaking Up - 6


【TV】 2007-11-28, 《淘小子看世界》 Breaking Up - 5


【TV】 2007-11-26, 《淘小子看世界》 Breaking Up - 4


【TV】 2007-11-23, 《淘小子看世界》 Breaking Up - 3


【TV】 2007-11-21, 《淘小子看世界》 Breaking Up - 2


【TV】 2007-11-19, 《淘小子看世界》 Breaking Up - 1




【TV】 2007-11-16, 《淘小子看世界》 The Turnaround - 9


【TV】 2007-11-14, 《淘小子看世界》 The Turnaround - 8


【TV】 2007-11-12, 《淘小子看世界》 The Turnaround - 7


【TV】 2007-11-09, 《淘小子看世界》 The Turnaround - 6


【TV】 2007-11-07, 《淘小子看世界》 The Turnaround - 5


【TV】 2007-11-05, 《淘小子看世界》 The Turnaround - 4


【TV】 2007-11-02, 《淘小子看世界》 The Turnaround - 3


【TV】 2007-10-31, 《淘小子看世界》 The Turnaround - 2


【TV】 2007-10-29, 《淘小子看世界》 The Turnaround - 1




【TV】 2007-10-26, 《淘小子看世界》 The Beard - 9


【TV】 2007-10-24, 《淘小子看世界》 The Beard - 8


【TV】 2007-10-22, 《淘小子看世界》 The Beard - 7


【TV】 2007-10-19, 《淘小子看世界》 The Beard - 6


【TV】 2007-10-17, 《淘小子看世界》 The Beard - 5


【TV】 2007-10-15, 《淘小子看世界》 The Beard - 4


【TV】 2007-10-12, 《淘小子看世界》 The Beard - 3


【TV】 2007-10-10, 《淘小子看世界》 The Beard - 2


【TV】 2007-10-08, 《淘小子看世界》 The Beard - 1




【TV】 2007-10-05, 《淘小子看世界》 Sister Theresa - 9


【TV】 2007-10-03, 《淘小子看世界》 Sister Theresa - 8


【TV】 2007-10-01, 《淘小子看世界》 Sister Theresa - 7


【TV】 2007-09-28, 《淘小子看世界》 Sister Theresa - 6


【TV】 2007-09-26, 《淘小子看世界》 Sister Theresa - 5


【TV】 2007-09-24, 《淘小子看世界》 Sister Theresa - 4


【TV】 2007-09-21, 《淘小子看世界》 Sister Theresa - 3


【TV】 2007-09-19, 《淘小子看世界》 Sister Theresa - 2


【TV】 2007-09-17, 《淘小子看世界》 Sister Theresa - 1




【TV】 2007-09-14, 《淘小子看世界》 Fear Strikes Out- 9


【TV】 2007-09-12, 《淘小子看世界》 Fear Strikes Out- 8


【TV】 2007-09-10, 《淘小子看世界》 Fear Strikes Out- 7


【TV】 2007-09-07, 《淘小子看世界》 Fear Strikes Out- 6


【TV】 2007-09-05, 《淘小子看世界》 Fear Strikes Out- 5


【TV】 2007-09-03, 《淘小子看世界》 Fear Strikes Out- 4


【TV】 2007-08-31, 《淘小子看世界》 Fear Strikes Out- 3


【TV】 2007-08-29, 《淘小子看世界》 Fear Strikes Out- 2


【TV】 2007-08-27, 《淘小子看世界》 Fear Strikes Out- 1




【TV】 2007-08-24, 《淘小子看世界》 Band on the Run - 9


【TV】 2007-08-22, 《淘小子看世界》 Band on the Run - 8


【TV】 2007-08-20, 《淘小子看世界》 Band on the Run - 7


【TV】 2007-08-18, 《淘小子看世界》 Band on the Run - 6


【TV】 2007-08-17, 《淘小子看世界》 Band on the Run - 5


【TV】 2007-08-16, 《淘小子看世界》 Band on the Run - 4


【TV】 2007-08-15, 《淘小子看世界》 Band on the Run - 3


【TV】 2007-08-14, 《淘小子看世界》 Band on the Run - 2


【TV】 2007-08-13, 《淘小子看世界》 Band on the Run - 1




【TV】 2007-08-11, 《淘小子看世界》 Wake Up, Little Cory - 9


【TV】 2007-08-10, 《淘小子看世界》 Wake Up, Little Cory - 8


【TV】 2007-08-09, 《淘小子看世界》 Wake Up, Little Cory - 7


【TV】 2007-08-08, 《淘小子看世界》 Wake Up, Little Cory - 6


【TV】 2007-08-07, 《淘小子看世界》 Wake Up, Little Cory - 5


【TV】 2007-08-06, 《淘小子看世界》 Wake Up, Little Cory - 4


【TV】 2007-08-04, 《淘小子看世界》 Wake Up, Little Cory - 3


【TV】 2007-08-03, 《淘小子看世界》 Wake Up, Little Cory - 2


【TV】 2007-08-02, 《淘小子看世界》 Wake Up, Little Cory - 1




【TV】 2007-08-01, 《淘小子看世界》 Who's Afraid of Cory Wolf? - 9


【TV】 2007-07-31, 《淘小子看世界》 Who's Afraid of Cory Wolf? - 8


【TV】 2007-07-30, 《淘小子看世界》 Who's Afraid of Cory Wolf? - 7


【TV】 2007-07-28, 《淘小子看世界》 Who's Afraid of Cory Wolf? - 6


【TV】 2007-07-27, 《淘小子看世界》 Who's Afraid of Cory Wolf? - 5


【TV】 2007-07-26, 《淘小子看世界》 Who's Afraid of Cory Wolf? - 4


【TV】 2007-07-25, 《淘小子看世界》 Who's Afraid of Cory Wolf? - 3


【TV】 2007-07-24, 《淘小子看世界》 Who's Afraid of Cory Wolf? - 2


【TV】 2007-07-23, 《淘小子看世界》 Who's Afraid of Cory Wolf? - 1




【TV】 2007-07-20, 《淘小子看世界》 Notorious - 9


【TV】 2007-07-19, 《淘小子看世界》 Notorious - 8


【TV】 2007-07-18, 《淘小子看世界》 Notorious - 7


【TV】 2007-07-17, 《淘小子看世界》 Notorious - 6


【TV】 2007-07-16, 《淘小子看世界》 Notorious - 5


【TV】 2007-07-13, 《淘小子看世界》 Notorious - 4


【TV】 2007-07-11, 《淘小子看世界》 Notorious - 3


【TV】 2007-07-09, 《淘小子看世界》 Notorious - 2


【TV】 2007-07-07, 《淘小子看世界》 Notorious - 1




【TV】 2007-07-06, 《淘小子看世界》 Pairing Off - 9


【TV】 2007-07-04, 《淘小子看世界》 Pairing Off - 8


【TV】 2007-07-02, 《淘小子看世界》 Pairing Off - 7


【TV】 2007-06-29, 《淘小子看世界》 Pairing Off - 6


【TV】 2007-06-27, 《淘小子看世界》 Pairing Off - 5


【TV】 2007-06-25, 《淘小子看世界》 Pairing Off - 4


【TV】 2007-06-22, 《淘小子看世界》 Pairing Off - 3


【TV】 2007-06-20, 《淘小子看世界》 Pairing Off - 2


【TV】 2007-06-18, 《淘小子看世界》 Pairing Off - 1




【美剧】 2007-06-15, 《淘小子看世界》 Back 2 School - 10


【美剧】 2007-06-13, 《淘小子看世界》 Back 2 School - 9


【美剧】 2007-06-11, 《淘小子看世界》 Back 2 School - 8


【美剧】 2007-06-08, 《淘小子看世界》 Back 2 School - 7


【美剧】 2007-06-06, 《淘小子看世界》 Back 2 School - 6


【美剧】 2007-06-04, 《淘小子看世界》 Back 2 School - 5


【美剧】 2007-06-01, 《淘小子看世界》 Back 2 School - 4


【美剧】 2007-05-30, 《淘小子看世界》 Back 2 School - 3


【美剧】 2007-05-28, 《淘小子看世界》 Back 2 School - 2


【美剧】 2007-05-25, 《淘小子看世界》 Back 2 School - 1




【美剧】 2007-05-18, 《淘小子看世界》 I Dream of Feeny-8


【美剧】 2007-05-14, 《淘小子看世界》 I Dream of Feeny-7


【美剧】 2007-05-11, 《淘小子看世界》 I Dream of Feeny-6


【美剧】 2007-05-07, 《淘小子看世界》 I Dream of Feeny-5


【美剧】 2007-05-04, 《淘小子看世界》 I Dream of Feeny-4


【美剧】 2007-04-30, 《淘小子看世界》 I Dream of Feeny-3


【美剧】 2007-04-27, 《淘小子看世界》 I Dream of Feeny-2


【美剧】 2007-04-23, 《淘小子看世界》 I Dream of Feeny-1




【美剧】 2007-04-20, 《淘小子看世界》 Boy Meets Girls-8


【美剧】 2007-04-16, 《淘小子看世界》 Boy Meets Girls-7


【美剧】 2007-04-13, 《淘小子看世界》 Boy Meets Girls-6


【美剧】 2007-04-09, 《淘小子看世界》 Boy Meets Girls-5


【美剧】 2007-04-06, 《淘小子看世界》 Boy Meets Girls-4


【美剧】 2007-04-02, 《淘小子看世界》 Boy Meets Girls-3


【美剧】 2007-03-30, 《淘小子看世界》 Boy Meets Girls-2


【美剧】 2007-03-26, 《淘小子看世界》 Boy Meets Girls-1




【美剧】 2007-03-19, 《淘小子看世界》The Play's the Thing - 7


【美剧】 2007-03-16, 《淘小子看世界》The Play's the Thing - 6


【美剧】 2007-03-12, 《淘小子看世界》The Play's the Thing - 5


【美剧】 2007-03-09, 《淘小子看世界》The Play's the Thing - 4


【美剧】 2007-03-05, 《淘小子看世界》The Play's the Thing - 3


【美剧】 2007-03-02, 《淘小子看世界》The Play's the Thing - 2


【美剧】 2007-02-26, 《淘小子看世界》The Play's the Thing - 1




【美剧】 2007-02-23, 《淘小子看世界》Kid Gloves - 9


【美剧】 2007-02-19, 《淘小子看世界》Kid Gloves - 8


【美剧】 2007-02-16, 《淘小子看世界》Kid Gloves - 7


【美剧】 2007-02-12, 《淘小子看世界》Kid Gloves - 6


【美剧】 2007-02-09, 《淘小子看世界》Kid Gloves - 5


【美剧】 2007-02-05, 《淘小子看世界》Kid Gloves - 4


【美剧】 2007-02-02, 《淘小子看世界》Kid Gloves - 3


【美剧】 2007-01-29, 《淘小子看世界》Kid Gloves - 2


【美剧】 2007-01-26, 《淘小子看世界》Kid Gloves - 1

Sunday, January 27, 2008

understand event of c#

Keywords: Event, delegate, Publish and subscribe pattern


我打算设计一个程序, 它能一次性美化一个目录之下所有的xml文件, 在UI上, 要求能显示处理的进度(即每处理完一个xml文件, UI的ProgressBar就变化一下). 美化xml的由SourcePackage类的BeautifyFiles方法完成, 而UI是另一个类FormMain. 显然这要处理SourcePackage类和FormMain类之间的通讯问题. 怎样解决这个问题呢? 这其实这是一个如何解耦的问题.


如果你学过C语言, 你会很自然想到使用回调函数, 即在FormMain类中新增一个方法, 比如UpdateProgressBar(), 然后将UpdateProgressBar()这个函数传给SourcePackage.BeautifyFiles()方法. 这确实是一个解决方法. 即将一个被调用者传给调用者. 这种方法直接有效, 但耦合度很高.


另一个方案是, 采用Publish-Subscribe模式, 使用这个模式, 首先要定义一个通知, 即发布什么, 以及订阅什么. 就本实例来讲, 这个通知就是一个xml文件已经被处理完了, 在UI类中, 订阅这个通知, 然后再编写这个通知的一个Handler函数(即进行更新进度条).


C#就是采用Publish-Subscribe来实现Event, 因为C#Delegate支持多播, 所以非常完美地实现了Publish-subscribe; 如果你使用C++, 也可采用了Observer模式来实现Event. 我们用C#的Event来实现设计要求. 设计的详细思路是:


在Publish方(Publish方多数为一个服务的服务端), 需要完成的工作是:


(1) 如果需要的话,使用delegate来定义通知类型, (一般的EventHandler已经在Framework中定义了, 特殊的Handler需要自定义)


public delegate void OneXmlProcessedEventHandler(object sender, ProcessCountEventArgs e);


(2) 在SourcePackage类中, 使用event关键字来发布通知.


public event OneXmlProcessedEventHandler OneXmlProcessed;


(3) 在SourcePackage.BeautifyFiles()触发这个通知的Handler.


foreach (Stream fileStream in m_ListFileStream)


{


m_FileBeautifier.FileStream = fileStream;


m_FileBeautifier.Beautify();


if (OneXmlProcessed != null)


{


eventArgs.ProcessedIndex = eventArgs.ProcessedIndex+1 ;


OneXmlProcessed(this, eventArgs);


}


}


在Subscribe方(Subscribe方多为服务的消费端), 需要完成的工作是:


(1) 订阅这个通知


SourcePackage sourcePackage = new SourcePackage(packageFullName);


sourcePackage.OneXmlProcessed += new OneXmlProcessedEventHandler(OneXmlProcessedHandler);



(2) 编写通知Handler


void OneXmlProcessedHandler(object sender, ProcessCountEventArgs e)


{


const string progressIndicator="{0} of {1} is proceeded!" ;


toolStripStatusLabel1.Text = string.Format(progressIndicator, e.ProcessedIndex, e.FileCount);


toolStripProgressBar1.Value = e.ProcessedIndex;


Application.DoEvents();


}







How to Access MediaMax by using FTP Client

Keywords: MediaMax, FTP


System requirements:


MediaMax FTP Gateway;


MS .net Framework 2.0


Any FTP client


Usage:


Notice, the MediaMax FTP Gateway does not support Secure FTP(SFTP), the actual transfer to MediaMax is made using a secure http link(HTTPS).


Step1, Run MediaMax FTP Gateway.


Step2, Config FTP client, Server: localhost, Port: 21, UserName: your MediaMax UserName, Password: your MediaMax Password


Step3: Config FTP client, Verify the Transfer queue worker is only 1(Maxinum simultaneous transfer value is to 1)

Friday, January 25, 2008

Zoundry blog writer alpha version evaluation

Keywords: Zoundry blog Writer, Zoundry Raven


从forum下载了最新的0.8.185版(code name:Raven), (下载地址http://forums.zoundry.com/viewforum.php?f=11&sid=f678b48d80ee5f7276d6a9248ba20795), 总体感觉, zoundry新版和1.04版相比的变化很大, 几个新特性非常适用:


(1) 支持模板, (2)支持FTP 和google Picasa storage, (3)支持Table的编辑


我认为还缺少一个重要的feature, 就是不支持proxy setting.

Thursday, January 24, 2008

Minimize software window to system tray


Keywords: Tools, Minimize software window to TrayIcon


Trayconizer, This is a cool little software. It allows you to minimize almost applications to system tray. Using Trayconizer is simple. To start TrayConizer on Notepad, you would execute: c:Path oTrayconizer.exe c:windows
otepad.exe


http://www.whitsoftdev.com/trayconizer/




Wednesday, January 23, 2008

Getting Started with NUnit

Getting Started with NUnit

Richard Davis, SharpLogic Software

In this article, we will take a look at unit testing, test-driven development, and the NUnit framework. If you are already familiar with these topics and are instead looking for information about how it all ties in with the Software Design Competition, feel free to skip ahead to the NUnit and the Software Design Competition section.

Prerequisite

Read and complete the steps described in the Getting Started With The Software Design Competition article. This will give you a cursory introduction to the process of using the NUnit GUI application to run test code.

Requirements and Setup

One of the great advantages of competing in the Imagine Cup Software Design Competition is that you’re able to use the best tools available, and they’re absolutely free!

  1. Download and install a version of Visual Studio 2005 Express from http://msdn.microsoft.com/vstudio/express/. You can use any language to develop your class library, but the baseline source code and tests are provided in C# so you’ll need to have that installed if you want to use them. Install with the default settings.

    Note: You may use any version of Visual Studio 2005 that you have available.

  1. Download the “NUnit 2.2.8 for .NET 2.0 MSI” installer from http://www.nunit.org/index.php?p=download and install it with the default settings.
  2. Download the practice Level 100 Tutorial challenge from http://imaginecup.sharplogic.com/Challenge.aspx?challenge=4265d098-52ac-4eb6-8549-e8ab652d99b8 and unzip it to a convenient location, such as “C:L100MathLib”. At this point you should have a directory structure that looks like the following:



Unzip the challenge package (C:L100MathLibL100Math.zip) to the “C:L100MathLib” directory so that its contents are placed into the “C:L100MathLibL100Math” directory. The resulting directory should look like the following:


Test-Driven Development and Unit Testing

Testing software is an integral phase of the development lifecycle. As software projects grow in size, so too does the complexity. Complexity can refer to the size of the source code base, architecture and design of components, number of code paths, and even algorithmic considerations. The decisions to be made about testing have to do with the “when” and the “how”, not the “why”.

Software testing provides a valuable means to help verify that software was build correctly, but it can also serve as a form of requirements specification up front. Consider the development of a method that computes the division of two integral numbers:

public int Divide(int dividend, int divisor)

{ }

To devise tests for this method we need to think like a tester. This process includes asking questions like the following:

  • What are the types of input and what is the set of values they can possess?
  • What is the expected return type? Are there any restrictions to be considered upon return to the caller?
  • If the input includes reference types, is null (C#) or nothing (VB.NET) ever passed in?

It is important to identify and test for cases where state and input lead to faulty operation. In the case of the Divide method, we can determine that the operation is invalid when the divisor input is zero. Next, we can write a test to exercise the Divide method and check for the desired response. In the case of the Divide method, we expect a System.DivideByZeroException to be thrown when the divisor input is zero.

The test method that we just devised is a type of unit test. Unit tests typically look for a very specific result from an operation. This means that there is often a many to one relationship of tests to one piece of code. Consider the Divide method once again. We already have one test designed, but we also want tests that make sure various valid inputs return the correct results.

As you can see from the Divide example, the development of unit tests can be done before the application code is implemented. This process is known as test-driven development, and it provides many benefits:

  • Requirements are self-documented.
  • Tests are automatic and repeatable.
  • Tests are designed to work with known bad and good input values.


The development of unit tests provides an automatic and repeatable method for verifying the correct functioning of code. Each time code is added or modified in a project, the suite of unit tests can be re-run to make sure that the changes did not break functionality that worked previously. The act of re-running a suite of unit tests is known as regression testing.

Keep in mind that unit testing does not guarantee that software will be free of bugs. Generally speaking, it is not realistic to get full code path coverage that exercises the entire set and combinations of input to all methods in a piece of software. In addition, the quality of testing relies solely on the developer of the tests. There may be cases where a unit test fails to identify problems in code. Nevertheless, test-driven development and unit testing are powerful allies to have throughout the software development lifecycle.

Developing Tests for NUnit

In this section, we will walk through the development of some simple unit tests that target the NUnit testing framework. Make sure that you have downloaded and installed the L100Math example as described in the Requirements and Setup section before continuing.

  1. Load the L100Math solution file with Visual Studio 2005:
  1. Double-click on the L100Math.sln file that you previously downloaded and extracted to your computer (C:L100MathLibL100MathL100Math.sln).
  1. Double-click on the MathHelperTests.cs source file.



  1. Examine the MathHelperTests class found within the MathHelperTests.cs source file. Notice that the test class has an attribute named TestFixture attached to it. This attribute is defined as part of the NUnit framework and is used by NUnit to determine which classes contain tests.
  2. Examine the test methods found within the MathHelperTests.cs source file:
  1. There are two test methods designed to test the functionality of the MathHelper.Add method, TestAdd and TestAdd2.
  1. Each test method is marked with the Test attribute so that NUnit can locate designated tests.
  2. Each test method is responsible for conducting tests in way that allows the NUnit framework to determine when a test is a success or failure. This is done by using the NUnit Assert class. In the TestAdd test method, we add 3 and 5 together and store the result. Next, the Assert.AreEqual method is given the expected result, the actual result, and a message to be presented to the user in case the provided values are not equal.



  1. Add a new test method to the MathHelperTests class which tests for the raising of a DivideByZeroException when the divisor parameter is zero:
  1. Copy and paste the following code:

    [Test]

    [ExpectedException(typeof(DivideByZeroException))]

    public void TestDivide2()

    {

int quotient = MathHelper.Divide(4, 0);

    }

  1. Here we used another NUnit framework attribute named ExpectedException to inform NUnit that the test will be considered a success if the specified DivideByZeroException exception type is thrown.
  2. Note that we could alternatively wrap the call to the MathHelper.Divide method within a try…catch block. The test will succeed in this case because we prevent the DivideByZeroException from being propagated up the call stack to the NUnit framework.

    [Test]

    public void TestDivide2()

    {

    try

    {

    int quotient = MathHelper.Divide(4, 0);

    Assert.Fail("MathHelper.Divide(4, 0) " +

    "failed to throw a DivideByZeroException.");

    }

    catch (DivideByZeroException)

    {

    }

    }

It is important to note the requirements for the most essential NUnit framework attributes, TestFixture and Test. TestFixture requires the following from the class that it is applied to:

  • Public scope.
  • A public, default constructor without parameters.

If a method that is marked with the TestFixture attribute does not have a default constructor with the correct signature, i.e. you marked it as private instead of public; all tests will fail to run. The reason will be listed under the Tests Not Run tab as shown below.

Note: You should just leave out the constructor unless you need to perform initialization.


The Test attribute requires the following from the method that it is applied to:

  • Public scope.
  • Void return type.
  • No parameters.

If a method that is marked with the Test attribute does not return void, the test will not be run by NUnit and the reason why will be listed under the Tests Not Run tab as shown below.



Assertions are another very important topic to become familiar with as you gain more experience using the NUnit platform. The Assert.AreEqual method, which we just saw in action, is categorized as an equality assertion by NUnit. Another type of equality assertion is the Assert.AreNotEqual method, which does exactly what its name implies. Other categories of assertion include identity, comparison, type, and condition. The following tables describe a number of the different assertion categories and their methods:

    Equality Asserts

    Method Description
    Assert.AreEqual Tests whether the expected and actual arguments are equal, asserting when they are not equal.
    Assert.AreNotEqual Opposite of AreEqual method.
    Examples
    // This example shows a successful AreEqual test.

    int expected = 5;

    int actual = 5;

    Assert.AreEqual(expected, actual, "Expected and actual values are not

    equal.");


Identity Asserts

Method Description
Assert.AreSame Tests whether the expected and actual arguments are the same object reference, asserting when they are not the same.
Assert.AreNotSame Opposite of AreSame method.
Assert.Contains Tests whether an object is contained in an array or list.
Examples
// This example shows a successful AreSame test.

object objA = new object();

object objB = objA;

Assert.AreSame(objA, objB, "Object references are not the same.");

// This example shows a successful Contains test.

string[] myArray = { "a", "b", "c" };

Assert.Contains("b", myArray, "Array does not contain expected

value.");


Comparison Asserts

Method Description
Assert.Greater Tests whether one object is greater than another.
Assert.Less Tests whether one object is less than another.
Examples
// This example shows a successful Less test (arg1 < arg2).

int arg1 = 5;

int arg2 = 6;

Assert.Less(arg1, arg2);


Type Asserts

Method Description
IsInstanceOfType Tests whether an object is of a specified type or derived from a specified type, asserting when it is not.
IsNotInstanceOfType Opposite of IsInstanceOfType method.
IsAssignableFrom Tests whether it is valid to assign an instance of the specified type to a given object, asserting if it is not.
IsNotAssignableFrom Opposite of IsAssignableFrom method.
Examples
// This example shows a successful IsInstanceOfType test.

Exception myException = new Exception();

Assert.IsInstanceOfType(typeof(Exception), myException);

// This example shows a successful IsAssignableFrom test.

object myObject = new object();

Assert.IsAssignableFrom(typeof(Exception), myObject);

Exception myException = new Exception();

// Assertion guarantees that myObject can be assigned myException (or // any other object that is typeof(Exception)).

myObject = myException;


Condition Asserts

Method Description
Assert.IsTrue Tests whether a boolean condition is true, asserting when it is not.
Assert.IsFalse Tests whether a boolean condition is false, asserting when it is.
Assert.IsNull Tests whether an object is null, asserting when it is not.
Assert.IsNotNull Opposite of IsNull method.
Assert.IsNaN Tests whether a double is not a number (NaN), asserting when it is not.
Assert.IsEmpty One overload tests whether a string is empty (string.Empty or “”), asserting when it is not.

Another overload tests whether a collection or array is empty, asserting when it is not.

Assert.IsNotEmpty Opposite of IsEmpty method.
Examples
// This example shows an unsuccessful IsNotEmpty test.

List<int> myList = new List<int>();

Assert.IsNotEmpty(myList, "List is empty.");


Utility Asserts

Method Description
Assert.Fail Throws an AssertionException with specified failure message.
Assert.Ignore Causes the current test to be ignored.
Examples
// This example shows a custom assertion that fails when the

// myDouble variable does not fit within the specified value range.

double myDouble = 0.94;

if (myDouble < 0.95 || myDouble > 1.05)

{

Assert.Fail("Value is not within the specified range.");

}


String Asserts

Method Description
StringAssert.Contains Tests whether a string contains an expected substring, asserting when it does not.
StringAssert.StartsWith Tests whether a string starts with an expected substring, asserting when it does not.
StringAssert.EndsWith Tests whether a string ends with an expected substring, asserting when it does not.
StringAssert.AreEqualIgnoringCase Tests whether an expected string is equal to an actual string ignoring case, asserting when they are not.
Examples
// This example shows a successful AreEqualIgnoringCase test.

string actual = "test";

StringAssert.AreEqualIgnoringCase("tEsT", actual);

Running Tests Using NUnit

Assuming that you satisfied the prerequisite listed at the beginning of this article, loading and running tests using the NUnit GUI should be a familiar process at this point. In this section, we will take a more detailed look at two ways in which tests can be run and results generated.

NUnit GUI Application

The NUnit GUI application provides a complete, easy to use interface with which you can load, select, and view the results for unit tests. As you are already aware, loading a test assembly is as simple as selecting File | Open. Once an assembly is loaded, the nunit-gui.exe application will continue to monitor the file for changes. If you make changes in Visual Studio and re-compile, the NUnit application will re-load the assembly automatically so that it remains in sync with your development.

  1. Build the solution by selecting Build | Build Solution from the main menu.

The NUnit GUI application works with .nunit project files, so any configuration options can be tied to an assembly and saved for future use. If you take a look at the L100MathTests project again, you will notice a file named L100MathTests.nunit. This file stores NUnit project configuration data in an XML format and it is added to the project as a matter of convenience.

Follow these steps to have Visual Studio open the NUnit project file using the NUnit-Gui.exe application by default:

  1. Right-click on L100MathTests.nunit and select Open With.
  2. Select the NUnit-Gui (NUnit) program followed by the Set as Default button.
  3. Select the OK button.


Now you can load the unit tests by simply double-clicking on the .nunit project file from Solution Explorer. If NUnit fails to launch, you may need to repeat steps 2-4, but this time add a new program to the list and navigate to the nunit-gui.exe application explicitly.


You can run all tests by selecting the root node and then selecting the Run button. If tests fail to meet the assertion criteria, informative messages will be placed in the Errors and Failures tab. A red node means that not all tests passed at that node or at its descendent nodes. Green indicates that all tests passed at a node and at its descendent nodes. It is also possible to run individual test classes or even individual tests within test classes. To do so, simply select the test node that you want to run and then select Run.

NUnit test results can be saved for future use by selecting Tools | Save Results as XML from the main menu. If you select the TestAdd method and run the test, the resulting XML document will include the following information:

<test-case name="L100MathTests.MathHelperTests.TestAdd" executed="True" success="False" time="0.047" asserts="0">

<failure>

<message><![CDATA[Tested: MathHelper.Add(3, 5)

expected: <8>

but was: <0>]]></message>

    <stack-trace><![CDATA[ at L100MathTests.MathHelperTests.TestAdd() in C:L100MathLibL100MathL100MathTestsMathHelperTests.cs:line 20

]]></stack-trace>

</failure>

</test-case>

This XML tells us that the TestAdd method was executed successfully but failed to meet the conditions of an assertion. A stack trace is also provided to let us know exactly where the assertion that failed is located.

NUnit Console Application

The NUnit console application is an alternative to the GUI application that is capable of performing tests and producing XML test results. As a quick demonstration, let’s use the NUnit console application to test the L100Math library we have been working with.

  1. Load a command prompt window by selecting Start | All Programs | Accessories | Command Prompt.
  2. Change the current directory to the location where the test DLL is created by Visual Studio when built as shown below.

  1. Temporarily modify the Path environment variable to include the path to the nunit-console.exe application. Use the following command:

    path=%path%;”c:Program FilesNUnit-Net-2.0 2.2.8bin”

  1. Use the NUnit console application to test all test methods contained within the L100MathTests.dll assembly:

    nunit-console L100MathTests.dll

    Once the NUnit console application has finished running tests, failure messages are output to the console window. If you see errors here, it is an indication that you should check the results XML file for more details. By default, NUnit will create the results XML file in the same directory where you performed the tests and name it TestResult.xml.

  1. Open the TestResult.xml file generated from the last test run. You can do this from an Explorer window or by issuing the command:

    notepad TestResult.xml


The NUnit console application can also use Visual Studio project files and NUnit project files to run tests, as show in the examples below:

    Nunit-console L100MathTests.csproj

    Nunit-console L100MathTests.nunit

Many other options are available for use with the NUnit console application. Please refer to the official NUnit documentation for more information.

NUnit and the Software Design Competition

Now that you understand how to write unit tests for the NUnit framework and use the associated tools, let’s take a moment to discuss how the Software Design Competition affects the testing environment and strategy. In this section, we will highlight important points that competitors will need to keep in mind as they develop, test, submit, and debug their entries.

The design and nature of the Software Design Competition has a number of effects upon user-submitted challenge entries:

  • Entries must be optimized enough so that they can complete the tests performed on the backend before a set timeout.
  • Entries must only use code that can run under the “Execution” permission set.

For some challenges, it may be difficult to know how much optimization is necessary because the backend tests are not available to you. One solution to this problem is to simply not worry about optimization unless you get a timeout message back from the testing server. A timeout message would be something like, “Test has exceeded timeout. 3000 ms.” If you get a timeout message, you will need to examine your solution for areas that need to be optimized.

User-submitted entries will only be given the ability to execute code as defined by the .NET code access security policy. This means that you can not use file I/O, sockets, networking, or other tasks that require more privileges. One way that you can ensure your code meets this requirement during testing is to add an appropriate PermissionSet attribute to the top of your classes. The L100Math library test class, MathHelperTests, shows this in action:

[TestFixture]

[PermissionSet(SecurityAction.PermitOnly, Name = "Execution")]

    public class MathHelperTests

Note that you will need to create a unit test in order to exercise all of your code for this attribute to have any affect. A security exception will not be thrown until code is executed that tries to do something that it does not have permission to do.

The design and nature of the Software Design Competition also has a number of effects upon the test suite used on the backend, as well as the test results seen by competitors:

  • Backend tests may be more complicated than basic unit tests and use multiple objects containing multiple asserts.
  • Backend test results are returned and presented to the competitor with failure messages only – stack traces are not made available.

An ideal unit test is designed to be as simple as possible to help eliminate the possible causes for failure when the test is run. However, the Software Design Competition has a need for a consistent number of unit tests to be performed at each difficulty level. Because of this, unit tests may be more complicated than is ideal. It is important to keep in mind that if a unit test has multiple assertions in it, only the first one will be reported. As a result, a unit test may continue to fail, even as you fix individual bugs.

Competitors will only have access to the failure messages retuned from the testing backend. This will be the only diagnostic information available to you as you develop your solution to challenges. As the challenges become more difficult, the failure messages will become less helpful. For example, Level 100 tests will likely explain the exact method call and parameters that failed, whereas Level 500 tests may only mention what the test was trying to accomplish.

You may run into the following types of failure messages as you progress further into the competition:

  • Failure message that indicates a specific method failed to return the expected results.
  • Failure message that indicates a method failed with specified input values.
  • Failure message that indicates an exception occurred in a specific method.
  • Failure message that only indicates an exception occurred (no other helpful information provided).
  • Failure message due to incorrect object inheritance.
  • Failure message due to missing interface implementation.

If you are having difficulty deciphering a failure message and know which method is causing the problem, try developing your own unit tests for it to see if you can determine the root cause for the problem. You may also want to re-consult the specification provided for the challenge to see if you missed any details pertinent to the problem at hand. Remember, there is no penalty for revising your entries and re-submitting them for scoring. However, only your most recent submission counts, so regression bugs can hurt you if you’re not careful.

Debugging NUnit Tests

Once you begin to develop unit tests you may wonder, “How do I test to make sure the tests are correct?” One tool that you have available is the Visual Studio Debugger. Being able to debug the unit tests is useful since it is one of the easiest ways to exercise our library code. In this section, we will demonstrate how you can take advantage of the debugger to test your unit code.

Let’s return to the L100Math library that we were working with earlier. Make sure that you have the L100Math solution file open in Visual Studio and the MathHelperTests.cs source file open for viewing.

There are some differences between the Visual Studio Express products and the other versions of Visual Studio that necessitate two different sets of steps to demonstrate debugging. Please choose the subsection below that applies to you.

Visual Studio Express

  1. Minimize all open programs so that your desktop is visible.
  2. Right-click on the desktop and select New | Shortcut.
  3. For the location of the shortcut, use the following:

    "C:Program FilesMicrosoft Visual Studio 8SDKv2.0GuiDebugdbgclr.exe"

  1. Select Next.
  2. Use the default name for the shortcut and select Finish.

At this point, you should have a shortcut on the desktop that launches the Microsoft CLR Debugger.


  1. Ensure that the current solution is built by selecting Build | Build Solution from the main menu in Visual Studio.
  2. Double-click on the L100MathTests.nunit file in Solution Explorer to launch the NUnit GUI application.
  3. Launch the debugger from the desktop shortcut.

  1. Select File | Open | File from the main menu of the debugger. This will open the Open File dialog box.

  1. Navigate to and open the MathHelperTests.cs source file.
  2. Place a breakpoint at the first line of the TestAdd method.

  1. Select Tools | Attach To Process from the main menu of the debugger.
  2. Locate and select the nunit-gui.exe process from the list of available processes.

  1. Select Attach to attach to the NUnit GUI process. At this point, the assembly containing the TestAdd method has not been called yet, so you will see a symbol where the breakpoint was set.
  2. Switch back to the NUnit GUI application and double-click on the TestAdd method. The breakpoint that you set should be hit and the CLR Debugger application brought back to the foreground.

  1. Select Debug | Step Into from the debugger main menu to enter the MathHelper.Add method.


Now that you know how to attach to the NUnit process, the full power of the Microsoft CLR Debugger is at your fingertips.

Visual Studio Standard or higher

  1. Place a breakpoint at the first line of the TestAdd method.

  1. Right-click on the L100MathTests project in Solution Explorer and select Properties.
  2. Select the Debug tab and fill in the following options:

    Start External Program text box: C:Program FilesNUnit-Net-2.0 2.2.8binnunit-gui.exe

    Command Line Arguments text box: L100MathTests.dll

    Working Directory text box: C:L100MathLibL100MathL100MathTestsbinDebug

  1. Select Debug | Start Debugging from the main menu or use the F5 shortcut.
  2. Switch to the NUnit GUI application and double-click on the TestAdd method. The breakpoint that you previously set should be hit and a yellow cursor and line will be shown.

  1. Select Debug | Step Into from the debugger main menu to enter the MathHelper.Add method.


Now that you know how to attach to the NUnit process, the full power of the Microsoft Visual Studio Debugger is at your fingertips.

Resources & References

Here are some addition resources that you may find helpful:

NUnit project - http://nunit.org/index.php?p=documentation

Wikipedia TDD - http://en.wikipedia.org/wiki/Test-driven_development

Wikipedia unit testing - http://en.wikipedia.org/wiki/Unit_test

MSDN unit testing article - http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnvs05/html/utfwvs05tmsys.asp

Wednesday, January 16, 2008

My string helper class in C#


Keywords: C#, string helper class.


下面的类是我经常会使用到的, 它是用来帮助从一个string中提取substring. 我在设计这些代码时, 主要考虑的是代码的易用性, 并没有太多地在意执行效率的问题. 注意:这些功能通常也可以通过正则表达式来实现, 但不如下面的代码来的快.




using System;
using System.Collections.Generic;
using System.Text;

namespace LiuHarry.Utils.Foundation
{
public class StrHelper
{


/// <summary>
/// return the first nested-substring of source string be contained in enveloped pattern.
/// </summary>
/// <param name="sourceStr">the entire source string</param>
/// <param name="leftSeparator">left separator string of pattern</param>
/// <param name="rightSeparator">right separator string of pattern</param>
/// <param name="patternEndIndex">pattern end index in source string </param>
/// <returns>nested-substring</returns>
private static string GetNestedString(string sourceStr, string leftSeparator, string rightSeparator, out int patternEndIndex)
{
patternEndIndex = -1;
if (String.IsNullOrEmpty(sourceStr) )
return null ;

int startIndex = sourceStr.IndexOf(leftSeparator);
if (startIndex<0)
return null ;
else
{
startIndex = startIndex + leftSeparator.Length;
}
int endIndex = sourceStr.IndexOf(rightSeparator, startIndex + 1);
if (endIndex<0)
{
return null;
}
else // "123##"67"
{
patternEndIndex = endIndex + rightSeparator.Length - 1;
}
string result = sourceStr.Substring(startIndex, endIndex - startIndex);
return result;
}


/// <summary>
/// return the first nested-substring of source string be contained in enveloped pattern in sourceStr.
/// </summary>
/// <param name="sourceStr">the entire source string</param>
/// <param name="leftSeparator">left separator string of pattern</param>
/// <param name="rightSeparator">right separator string of pattern</param>
/// <returns>nested-substring</returns>
public static string GetNestedSubString(string sourceStr, string leftSeparator, string rightSeparator)
{
int patternEndIndex;
return GetNestedString(sourceStr, leftSeparator, rightSeparator, out patternEndIndex);
}




/// <summary>
/// return given ignoreMatchedCount nested-substring of source string be contained in enveloped pattern
/// </summary>
/// <param name="sourceStr">the entire source string</param>
/// <param name="leftSeparator">left separator string of pattern</param>
/// <param name="rightSeparator">right separator string of pattern</param>
/// /// <param name="ignoreMatchedCount">ignore the match pattern count</param>
/// <returns>nested-substring</returns>
public static string GetNestedSubString(string sourceStr,string leftSeparator,string rightSeparator,int ignoreMatchedCount)
{
int patternEndIndex;
string tempStr = sourceStr;
string resultStr = null ;
for (int i=0;i<=ignoreMatchedCount;i++)
{
resultStr = GetNestedString(tempStr, leftSeparator, rightSeparator, out patternEndIndex);
tempStr = tempStr.Substring(patternEndIndex+1);
}
return resultStr;
}



/// <summary>
/// return all nested-substring of source string be contained in enveloped pattern
/// </summary>
/// <param name="sourceStr">the entire source string </param>
/// <param name="leftSeparator">left separator string of pattern</param>
/// <param name="rightSeparator">right separator string of pattern</param>
/// <returns>a List<string> collection of all nested-substring </returns>
public static List<string> GetAllNestedSubString(string sourceStr, string leftSeparator, string rightSeparator)
{
List<string> listNestedSubStr = new List<string>();
int ignoreMatchedCount= 0 ;
string nestSubStr=null ;
while (true )
{
nestSubStr=GetNestedSubString( sourceStr, leftSeparator, rightSeparator,ignoreMatchedCount);
if (nestSubStr==null)
break ;
else
{
listNestedSubStr.Add(nestSubStr);
ignoreMatchedCount = ignoreMatchedCount+1;
}
}
return listNestedSubStr ;
}
}
}