1. Trang chủ
  2. » Công Nghệ Thông Tin

Pro .NET 2.0 Extreme Programming 2006 phần 6 pdf

34 342 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Pro .NET 2.0 Extreme Programming 2006 phần 6 pdf
Trường học University of Example
Chuyên ngành Computer Science
Thể loại Sách kỹ năng lập trình
Năm xuất bản 2006
Thành phố Unknown
Định dạng
Số trang 34
Dung lượng 206,74 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Build Query to Database to Validate Username and Password Task The Login user story has one business class User.cs and one data class UserData.cs that need unit tests.. public void Init{

Trang 1

Developing the Login User Story

The first user story that we are going to develop is Login In iteration planning (Chapter 12),

this story was broken down into the following tasks:

• Create login screen

• Create text entry fields for username and password

• Build query to database to validate username and password

• Determine login request success or failureBefore you begin, you need to clean up the Northwind solution you created in Appendix

A Delete any empty (default) classes that were autogenerated by the IDE (Class1.cs) or web

pages (WebPage1.aspx or Default.aspx) and any test classes you created (CategoryTests.cs

and the associated Category.cs class) If you did not create the Northwind solution in

Appendix A, do that now

The first task that you are going to work on is the one to validate the username and word against the database

application The source code is intentionally kept as basic and simple as possible, so that you can focus on

the XP technique of developing software in a NET environment Apress has many great books on C# and the

.NET Framework that you can refer to for thorough coverage of those topics

Build Query to Database to Validate Username and Password Task

The Login user story has one business class (User.cs) and one data class (UserData.cs) that

need unit tests You are going to code iteratively, so you will start with the smallest unit test

possible

Using the test-driven development approach, you start with the UserTests.cs file shown

in Listing 13-1, which you need to add to the TestLayer project You will need to add a

refer-ence to the BusinessLayer and DataLayer projects on the TestLayer project, if you have not

done so already

Listing 13-1.UserTests.cs File

#region Using directives

Trang 2

public void Init(){

}[TearDown]

public void Destroy(){

}[Test]

public void TestGetUser(){

UserData userData = new UserData();

Assert.IsNotNull(userData.GetUser("bogususer", "password"),

"GetUser returned a null value, gasp!");

}}}

If you build the solution now, you will get several errors because your web applicationdoes not have a concept of a UserData class To address that issue, you will need to define aminimal UserData class so you can successfully build but not pass the test Listing 13-2 showsthe minimal UserData.cs file that needs to be added to the DataLayer project You will need toadd a reference to the BusinessLayer project on the DataLayer project, if you have not done soalready

Listing 13-2.Minimal UserData.cs File

#region Using directives

Trang 3

}public User GetUser(string username, string password){

User user = null;

return user;

}}}

Set the TestLayer project as the startup project and build the solution You still get piler errors—although the UserData class is now defined, you introduced another class (User)

com-that is yet to be defined

Listing 13-3 shows the minimal source for the User.cs class that needs to be added to theBusinessLayer project

Listing 13-3.Minimal User.cs File

#region Using directive

}}}

Trang 4

USING A MOCK OBJECT

If the database had not been ready when you started coding this portion of the user story, you could haveused a mock object here instead To do that, you would first add a reference to the NMock DLL (nmock.dll)

to the TestLayer project Next, you would create an interface class called IUserData.cs that looks likethe following

#region Using directivesusing System;

using System.Collections.Generic;

using System.Text;

using BusinessLayer;

#endregionnamespace DataLayer{

interface IuserData{

User GetUser(string username, string password);

}}Then you would make the UserTests.cs class look like the following

#region Using directivesusing System;

[TestFixture]

public class UserTests{

public UserTests(){

}[SetUp]

public void Init(){

}

Trang 5

public void Destroy(){

}[Test]

public void TestGetUser(){

DynamicMock userData = new DynamicMock (typeof(IUserData));

Assert.IsNotNull(userData.GetUser("bogususer", "password"),

"GetUser returned a null value, gasp!");

}}}When the database became available, you would implement the UserData.cs class as shown inListing 13-2 and have the UserData class inherit (implement) the IUserData interface At that time, youwould also update the UserTests.cs class to use the UserData.cs class instead of the mock object youimplemented

Now rebuild and run the solution You will not get any compiler errors, but when the testexecutes, the test fails That’s because you are simply returning a null value for the user Let’s

fix that first Start by modifying the UserData.cs file as shown in Listing 13-4

Listing 13-4.Modified UserData.cs File

#region Using directives

}

Trang 6

public User GetUser(string username, string password){

User user = null;

user = new User();

return user;

}}}

Notice that you just wrote a test, coded a little, and then refactored This is the codinghabit you want to develop Once you have adopted this style of coding, you will find that youwill produce fewer bugs and have a greater sense that the quality of the code you are creating

is continually getting better

Now when you rebuild the solution, it builds just fine and your test passes, but nothing ofany significance is really happening To take the next step, you need to modify your UserDataclass to connect to the Northwind database to get the user’s role, along with the username andpassword, using the username and password passed to the UserData class from the UserTestsclass Listing 13-5 shows the UserData.cs file with these changes

Listing 13-5.UserData.cs File Modified to Connect to the Database

#region Using directives

private static string connectionString =

"Driver={Microsoft Access Driver (*.mdb)};" +

"DBQ=c:\\xpnet\\database\\Northwind.mdb";

public UserData(){

}public User GetUser(string username, string password){

User user = null;

Trang 7

try{OdbcConnection dataConnection = new OdbcConnection();

OdbcDataReader dataReader = dataCommand.ExecuteReader();

// Make sure that we found our user

if ( dataReader.Read() ){

user = new User(dataReader.GetString(0),dataReader.GetString(1));

}dataConnection.Close();

}catch(Exception e){

Console.WriteLine("Error: " + e.Message);

}return user;

}}}

When you rebuild the solution now, you have a compile error because you don’t have aUser class that has a constructor that takes arguments Listing 13-6 shows the change to the

User class

Trang 8

Listing 13-6.Modified User.cs File

#region Using directives

private string userName;

private string password;

public User(){

}public User(string userName, string password){

this.userName = userName;

this.password = password;

}}}

Lastly, you need to enhance the UserTests class to pass a username and password to theUserData class Since this is a test, you need to create test data that you feel confident will notexist in the database That way, you can set up the data and remove it when your test has com-pleted safely You will refactor the database connections better later, but for now, you will takethe simplest approach possible Listing 13-7 shows the modifications to the UserTests.cs file

Listing 13-7.Modified UserTests.cs File

#region Using directives

Trang 9

// Build connection stringconnectionString =

new StringBuilder("Driver={Microsoft Access Driver (*.mdb)}");

connectionString.Append(";DBQ=c:\\xpnet\\database\Northwind.mdb");

}[SetUp]

public void Init(){

try{OdbcConnection dataConnection = new OdbcConnection();

commandText.Append(" VALUES ('bogususer', 'password')");

dataCommand.CommandText = commandText.ToString();

int rows = dataCommand.ExecuteNonQuery();

// Make sure that the INSERT workedAssert.AreEqual(1, rows, "Unexpected row count returned.");

dataConnection.Close();

}catch(Exception e){

Assert.Fail("Error: " + e.Message);

}}

Trang 10

public void Destroy(){

try{OdbcConnection dataConnection = new OdbcConnection();

int rows = dataCommand.ExecuteNonQuery();

// Make sure that the DELETE worked Assert.AreEqual(1, rows, "Unexpected row count returned");

dataConnection.Close();

}catch(Exception e){

Assert.Fail("Error: " + e.Message);

}}[Test]

public void TestGetUser(){

UserData userData = new UserData();

Assert.IsNotNull(userData.GetUser("bogususer", "password"),

"GetUser returned a null value, gasp!");

}}}

Rebuild the solution again and run your tests If you get any errors, look at the build orruntime output to see where the error occurred

Don’t forget that testing is not just all “happy day” scenarios Add a negative test whereyou pass in a bad username and password, as shown in Listing 13-8 In this test, you shouldexpect to get a null user back, since the user should not exist in the database

Trang 11

Listing 13-8.Negative Test for UserTests.cs

#region Using directives

// Build connection stringconnectionString =

new StringBuilder("Driver={Microsoft Access Driver (*.mdb)}");

connectionString.Append(";DBQ=c:\\xpnet\\database\Northwind.mdb");

}[SetUp]

public void Init(){

try{OdbcConnection dataConnection = new OdbcConnection();

commandText.Append(" VALUES ('bogususer', 'password')");

dataCommand.CommandText = commandText.ToString();

Trang 12

int rows = dataCommand.ExecuteNonQuery();

// Make sure that the INSERT workedAssert.AreEqual(1, rows, "Unexpected row count returned.");

dataConnection.Close();

}catch(Exception e){

Assert.Fail("Error: " + e.Message);

}}[TearDown]

public void Destroy(){

try{OdbcConnection dataConnection = new OdbcConnection();

dataConnection.ConnectionString = connectionString.ToString();dataConnection.Open();

OdbcCommand dataCommand = new OdbcCommand();

dataCommand.Connection = dataConnection;

// Build command stringStringBuilder commandText =new StringBuilder("DELETE FROM Users WHERE username='bogususer'");dataCommand.CommandText = commandText.ToString();

int rows = dataCommand.ExecuteNonQuery();

// Make sure that the DELETE worked Assert.AreEqual(1, rows, "Unexpected row count returned");

dataConnection.Close();

}catch(Exception e){

Assert.Fail("Error: " + e.Message);

}}

Trang 13

public void NegativeTestGetUser(){

UserData userData = new UserData();

Assert.IsNull(userData.GetUser("", ""),

"GetUser did not return a null value, gasp!");

}}}

Rebuild the solution and run the test again This time two tests should run, and bothshould pass successfully

Let’s move on to the Create Login Screen task for the Login user story

Create Login Screen Task

For the Create Login Screen task, you are going to add a new web form (.aspx) to the

NorthwindWeb project Name that web page Login.aspx Switch to the Source view of the file

and make it look like the code in Listing 13-9

Listing 13-9.Login.aspx File

<%@ Page language="C#" CodeFile="login.aspx.cs" Inherits=”Login_aspx %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"

<asp:Label ID="titleLabel" style="z-index: 104;

left: 427px; position: absolute; top: 56px"

Runat="server">Northwind Login</asp:Label>

Trang 14

<asp:Button ID="submitButton" OnClick="SubmitButton_Click"

Next, let’s tackle creating the text-entry fields for the login screen

Create Text Entry Fields for Username and Password Task

Now you need to add the data-entry fields to the login screen You will pass the entered name and password to the UserData.cs class for validation To accomplish this, you need tomake the Login.aspx file (Source view) look like Listing 13-11

user-Listing 13-11.Modified Login.aspx File

<%@ Page language="C#" CodeFile="login.aspx.cs" Inherits=”Login_aspx %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"

<asp:Label ID="titleLabel" style="z-index: 104;

left: 427px; position: absolute; top: 56px"

Runat="server">Northwind Login</asp:Label>

Trang 15

<asp:Label ID="usernameLabel" style="z-index: 101;

left: 362px; position: absolute; top: 126px"

Runat="server">Username:</asp:Label>

<asp:Label ID="passwordLabel" style="z-index: 102;

left: 364px; position: absolute; top: 184px"

Runat="server">Password:</asp:Label>

<asp:TextBox ID="usernameTextBox" style="z-index: 103;

left: 452px; position: absolute; top: 121px" TabIndex="1"

Runat="server" Width="145px" Height="22px">

</asp:TextBox>

<input style="z-index: 106; left: 451px; width: 145px;

position: absolute; top: 181px; height: 22px" tabindex="2"

type="password" name="passwordTextBox" id="passwordTextBox" />

<asp:Button ID="submitButton" OnClick="SubmitButton_Click"

Then enhance the Login.aspx.cs file as shown in Listing 13-12

Listing 13-12.Modified Login.aspx.cs File

string passwordText = Request.Params["passwordTextBox"];

UserData userData = new UserData();

User user = userData.GetUser(usernameTextBox.Text, passwordText);

}}

That’s it for this task Let’s move to the last one for this user story

Determine Login Request Success or Failure Task

Lastly, you need to give the users an indication of whether or not they successfully logged in

First, enhance the Login.aspx file as shown in Listing 13-13

Trang 16

Listing 13-13.Further Modifications to Login.aspx

<%@ Page language="C#" CodeFile="login.aspx.cs" Inherits="Login_aspx %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"

<asp:Label ID="titleLabel" style="z-index: 104;

left: 427px; position: absolute; top: 56px"

Runat="server">Northwind Login</asp:Label>

<asp:Label id="usernameLabel" style="z-index: 101;

left: 362px; position: absolute; top: 126px"

Runat="server">Username:</asp:Label>

<asp:Label ID="passwordLabel" style="z-index: 102;

left: 364px; position: absolute; top: 184px"

Runat="server">Password:</asp:Label>

<asp:TextBox ID="usernameTextBox" style="z-index: 103;

left: 452px; position: absolute; top: 121px" TabIndex="1"

Runat="server" Width="145px" Height="22px">

</asp:TextBox>

<input style="z-index: 106; left: 451px; width: 145px;

position: absolute; top: 181px; height: 22px" tabindex="2"

type="password" name="passwordTextBox" id="passwordTextBox" />

<asp:Button ID="submitButton" OnClick="SubmitButton_Click"

style="z-index: 105;

left: 576px; position: absolute; top: 231px"TabIndex="3"

Runat="server" Text="Login">

</asp:Button>

<asp:Label ID="successLabel" style="z-index: 107;

left: 332px; position: absolute; top: 311px"

Runat="server" Width="389px" Visible="False">

Trang 17

Listing 13-14.Further Modifications to Login.aspx.cs

string passwordText = Request.Params["passwordTextBox"];

UserData userData = new UserData();

User user = userData.GetUser(usernameTextBox.Text, passwordText);

successLabel.Visible = true;

if (user != null){

// Go to main NorthwindWeb page eventually// But for now, just display a success messagesuccessLabel.Text = "User login succeeded, woohoo!";

}else{// Go back to this page to let the user try againsuccessLabel.Text = "User login failed, gasp!";

}}}

Now run your unit test to see if everything is passing Make sure that the TestLayer project

is set as the startup project Then rebuild the solution If everything built correctly, start the

TestLayer project by selecting Build ➤Start (or by pressing F5) Then click the Run button to

execute the unit tests You should get a green bar

Next, set the startup project to the NorthwindWeb project and Login.aspx as the start page

This will allow you to see your code in action, as a user would If all goes well, your web

browser should pop up and display the login web page

So, you have completed all the defined tasks for the Login user story You created a loginscreen with text-entry fields for the username and password, and you processed the login

request by verifying the username and password against the database You then determined if

the user successfully logged in and displayed either a success or failure message You also

cre-ated both positive and negative tests against the business layer of the web application You

have successfully completed your part of the user story as far as you know, but the user story is

not completed until the user story has been accepted by the customer For acceptance of the

user story, the customer must define the acceptance criteria with the help of the acceptance

tester, as discussed in the “Other Team Members’ Duties” section later in the chapter

Now let’s work on another user story

Ngày đăng: 12/08/2014, 21:22

TỪ KHÓA LIÊN QUAN