Wednesday, February 26, 2014

Bulk update in Entity Framework


In Entity Framework, updating records are very simple. But how it is working behind the screen?


Consider below example.

Genre gnr= context.Genres.First(g => g.Name=="Rock");
gnr.Description = "Really Rocking!";
context.SaveChanges();



It is updating single record. When 'context.SaveChanges()' executes, it will pass the following statement to sql server.

exec sp_executesql N'UPDATE [dbo].[Genres]
SET [Description] = @0
WHERE ([GenreID] = @1)',
N'@0 nvarchar(max) ,@1 int',@0=N'Really Rocking!',@1=17


Well, It is using the primary id field to update the record.


Consider a scenario like we want to update a bunch of records. For example, I am trying to update all the Null Descripton with 'Tested OK' in Genres table'.

context.Genres
    .Where(g => g.Description == null)
    .ToList<Genre>()
    .ForEach(g => g.Description = "Tested OK");
context.SaveChanges();


The 'SaveChanges' passed a list of statements to SQL Server.

exec sp_executesql N'UPDATE [dbo].[Genres]
SET [Description] = @0
WHERE ([GenreID] = @1)
',N'@0 nvarchar(max) ,@1 int',@0=N'Tested OK',@1=1
go
exec sp_executesql N'UPDATE [dbo].[Genres]
SET [Description] = @0
WHERE ([GenreID] = @1)
',N'@0 nvarchar(max) ,@1 int',@0=N'Tested OK',@1=2
go
exec sp_executesql N'UPDATE [dbo].[Genres]
SET [Description] = @0
WHERE ([GenreID] = @1)
',N'@0 nvarchar(max) ,@1 int',@0=N'Tested OK',@1=3
go
exec sp_executesql N'UPDATE [dbo].[Genres]
SET [Description] = @0
WHERE ([GenreID] = @1)
',N'@0 nvarchar(max) ,@1 int',@0=N'Tested OK',@1=4
go


Here also Entity Framework uses the same strategy. Updating the each record using its primary Id.

Consider deleting multiple records

context.Genres
    .Where(g => g.Description == null)
    .ToList<Genre>()
    .ForEach(g => context.Genres.Remove(g));
context.SaveChanges();


This will produce a list of delete statements also as below.

exec sp_executesql N'DELETE [dbo].[Genres]
WHERE ([GenreID] = @0)',N'@0 int',@0=19
go
exec sp_executesql N'DELETE [dbo].[Genres]
WHERE ([GenreID] = @0)',N'@0 int',@0=20
go
exec sp_executesql N'DELETE [dbo].[Genres]
WHERE ([GenreID] = @0)',N'@0 int',@0=21
go


The Entity Framework always execute SQL statements record-wise. It uses the filters to set the status inside the Entity Model and updates the modifications one by one.But this will create more traffic in network and will affect the performance. Entity Framework lacks the ability to update or delete multiple records using a single SQL statement.

To resolve this Mr.Paul Welter has designed Entity Framework Extended Library. It can be installed from NuGet package manager. It can be found by searching with 'EntityFramework.Extended'. After installation, EntityFramework.Extended dll will be added to the project reference. It should be refered in the page with the following statement

using EntityFramework.Extensions;

Now our 'context' object will have added 'Upadate<>' and 'Delete<>' methods.

Here is the update statement using the extended library

context.Genres.Update(g => g.Description == null, g => new Genre { Description = "Tested OK" });

It accepts two parameters. First one is the filter and the second one is a new object with modified values.

This will update all records with the null description with the single statement

exec sp_executesql N'UPDATE [dbo].[Genres] SET
[Description] = @p__update__0
FROM [dbo].[Genres] AS j0 INNER JOIN (
SELECT
    [Extent1].[GenreID] AS [GenreID]
    FROM [dbo].[Genres] AS [Extent1]
    WHERE [Extent1].[Description] IS NULL
) AS j1 ON (j0.[GenreID] = j1.[GenreID])',N'@p__update__0 nvarchar(9)',@p__update__0=N'Tested OK'



The Delete statement is also a kind of same.

context.Genres.Delete(g => g.Description==null);

It will delete multiple records with the help of the below statement.

DELETE [dbo].[Genres]
FROM [dbo].[Genres] AS j0 INNER JOIN (
SELECT
    [Extent1].[GenreID] AS [GenreID]
    FROM [dbo].[Genres] AS [Extent1]
    WHERE [Extent1].[Description] IS NULL
) AS j1 ON (j0.[GenreID] = j1.[GenreID])


Note that, we haven't used the 'SaveChanges' call to the context object. Both 'Update' and 'Delete' will execute directly.


Happy coding...





Wednesday, February 5, 2014

Frequently used 15 LINQ 2 SQL statements

As a .Net developer,you would be very familiar with the SQL Statements. With Entity Framework 4, LINQ to SQL  is replacing the old SQL statements. Understanding LINQ to SQL  is becoming crucial for .NET developers. Here I am listing frequently used 15 SQL Statements and  corresponding LINQ to SQL statements.

Data Model

Consider an online payment system. It will have a list of clients and payments will be processed on behalf of these clients. Periodically they have to settle their payments with the clients. To store this data, we have 4 tables – Transactions,Payments,SettledTransactions and ClientMaster. Here the Transactions table will have the details of payment transactions made by the users. The Payments table will have the card specific details used in these payments. Once settled, the transactions will be saved into the SettledTransactions table with an SLID. ClientMaster will have the list of Clients

Here is the structure. Only the relevant fields are listed

Transactions
SettledTransactions
Payments
ClientMaster
tx_no
tx_no
tx_no
client_code
client_code
client_code
client_code
client_name
tx_date
slid
card_type










Statements

1 Simple Select
SQL Statement Select * from Transactions t
Where t.Client_code='CL0011'
LINQ Statement Var selectlist = from t in contex.Transactions
where t.client_code==”CL0011”
select t
LINQ with Lambda Expression var selectlist = context.Transactions
.Where(t => t.Client_Code == "CL0011")
.Select(t => t)
2 Select Specific Columns
SQL Statement Select t.tx_no,t.tx_date from Transactions t
Where t.Client_code='CL0011'
LINQ Statement var selectlist = from t in contex.Transactions
where t.client_code==”CL0011”
select new {t.tx_no,t.tx_date}
LINQ with Lambda Expression var selectlist = context.Transactions
.Where(t => t.Client_Code == "CL0011")
.Select(t => new {t.tx_no,t.tx_date})
3 Sort by Single Field
SQL Statement Select t.tx_no,t.tx_date from Transactions t
Where t.Client_code='CL0011' order by t.tx_date
LINQ Statement var selectlist = from t in contex.Transactions
where t.client_code==”CL0011”
orderby t.tx_date
select new {t.tx_no,t.tx_date}
LINQ with Lambda Expression var selectlist = context.Transactions
.Where(t => t.Client_Code == "CL0011")
.OrderBy(t => t.tx_date)
.Select(t => new {t.tx_no,t.tx_date})
4 Sort by Multiple Fields
SQL Statement Select t.tx_no,t.tx_date from Transactions t
Where t.Client_code='CL0011 order by t.tx_date desc,t.tx_no desc
LINQ Statement var selectlist = from t in contex.Transactions
where t.client_code==”CL0011”
orderby t.tx_date descending,t.tx_no descending
select new {t.tx_no,t.tx_date}
LINQ with Lambda Expression var selectlist = context.Transactions
.Where(t => t.Client_Code == "CL0011")
.OrderByDescending(t => new { t.tx_date, t.tx_no })
.Select(t => new {t.tx_no,t.tx_date})
5 Simple Aggregate
SQL Statement select count(*) from Transactions t where t.client_code='CL0011'
LINQ Statement var cnt = (from t in context.Transactions
where t.Client_Code == "CL0011"
Select t).Count();
LINQ with Lambda Expression var cnt = context.Transactions
.Where(t => t.Client_Code == "CL0011")
.Count()
6 With GROUP BY Clause
SQL Statement select client_code,count(*) from Transactions t group by client_code
LINQ Statement var summary = from t in context.Transactions
group t by t.Client_Code into c
select new { client = c.Key, TxCount = c.Count() };
LINQ with Lambda Expression var summary = context.Transactions
.GroupBy(t => t.Client_Code)
.Select( g => new {client=g.Key,TxCount=g.Count()});
Remarks
7 Multiple GROUP BY clause
SQL Statement select client_code,tx_date,count(*) from Transactions t group by client_code,tx_date order by client_code,tx_date
LINQ Statement var summary = from t in context.Transactions
group t by new { t.Client_Code,t.tx_date } into c
orderby c.Key.Client_Code,c.Key.tx_date
Select new
{
client = c.Key.Client_Code,
busdate=c.Key.tx_date,
txcount = c.Count(),
txAmount = (from t in c select t.total_amount).Sum()

};
LINQ with Lambda Expression var summary = context.Transactions
.GroupBy(t => new { t.Client_Code, t.tx_date })
.OrderBy(g => new { g.Key.Client_Code, g.Key.tx_date })
.Select(c => new
{
client = c.Key.Client_Code,
busdate = c.Key.tx_date,
txcount = c.Count(),
txAmount =c.Sum(t => t.total_amount)

});
8 With HAVING Clause
SQL Statement select client_code,tx_date,SUM(total_amount) from Transactions t
group by client_code,tx_date
having SUM(total_amount)<0
order by client_code,tx_date
LINQ Statement var summary = from t in context.Transactions
group t by new { t.Client_Code, t.tx_date } into c
where (from t in c select t.total_amount).Sum() < 0
orderby c.Key.Client_Code, c.Key.tx_date
select new
{
client = c.Key.Client_Code,
busdate = c.Key.tx_date,
txcount = c.Count(),
txAmount = (from t in c select t.total_amount).Sum()

};
LINQ with Lambda Expression var summary = context.Transactions
.GroupBy(t => new { t.Client_Code, t.tx_date })
.OrderBy(g => new { g.Key.Client_Code, g.Key.tx_date })
.Where(g => g.Sum(t => t.total_amount)<0)
.Select(c => new
{
client = c.Key.Client_Code,
busdate = c.Key.tx_date,
txcount = c.Count(),
txAmount = c.Sum(t => t.total_amount)

});
9 Distinct Clause
SQL Statment select distinct client_code from Transactions
LINQ Statement var selectlist = (from t in context.Transactions
select new { t.Client_Code }).Distinct();
LINQ with Lambda Expression var selectlist = context.Transactions
.Select(t => new { t.Client_Code}).Distinct();
10 Top 10
SQL Statement select top 10 t.tx_no from Transactions t
where t.Client_Code='CL0011'
order by t.tx_no desc
LINQ Statement var selectlist = (from t in context.Transactions
where t.Client_Code == "CL0011"
orderby t.tx_no descending
select new { t.tx_no }).Take(10);
LINQ with Lambda Expression var selectlist = context.Transactions
.Where(t => t.Client_Code == "CL0011")
.OrderByDescending(t => t.tx_no)
.Select(t => new { t.tx_no }).Take(10);
11 Inner Join
SQL Statement select c.client_name,t.tx_no from Transactions t
inner join ClientMaster c on t.Client_Code= c.client_code
where t.Client_Code='CL0011'
LINQ Statement var selectlist = from t in context.Transactions
join c in context.ClientMaster on t.Client_Code equals c.client_code
where c.client_code=="CL0011"
select new { t.tx_no, c.client_name };
LINQ with Lambda Expression var selectlist = context.Transactions
.Join(context.ClientMaster,
t => t.Client_Code,
C => c.client_code,(t,c) => new {t,c} )
.Where(t => t.t.Client_Code=="CL0011")
.Select(r => new {r.c.client_name,r.t.tx_no});
Note There is more advanced Navigational Properties in EF for getting values from the associated Entity Sets. Join statements are useful when there is no association between the Entity Sets
12 Multiple Inner Join
SQL Statement select t.tx_no,p.card_type,c.client_name from Transactions t
inner join ClientMaster c on t.Client_Code= c.client_code
inner join Payments p on t.Client_Code=p.Client_Code
and t.tx_no=p.tx_no where t.Client_Code='CL0011'
LINQ Statement var selectlist=from t in context.Transactions
join c in context.ClientMaster on t.Client_Code equals c.client_code
join p in context.Payments on new {a = t.Client_Code,b = t.tx_no }
equals new {a = p.Client_Code, b = p.tx_no}
Where c.client_code=="CL0011"
select new { t.tx_no,c.client_name,p.card_type};
LINQ with Lambda Expression var selectlist = context.Transactions
.Join(context.ClientMaster.Where(c=>c.client_code=="CL0011"),
t => t.Client_Code, c => c.client_code, (t, c) => new { t, c })
.Join(context.Payments, t => new { a = t.t.Client_Code, b = t.t.tx_no },
p => new { a = p.Client_Code, b = p.tx_no }, (t, p) => new { t, p })
.Select(r => new { r.t.t.tx_no, r.t.c.client_name, r.p.card_type });
13 Left Join
SQL Statement select t.tx_no,s.slid from Transactions t
left join SettledTransactions s
on t.Client_Code= s.client_code and t.tx_no=s.tx_no
where t.Client_Code='CL0011'
LINQ Statement var selectlist = from t in context.Transactions
where t.Client_Code=="CL0011"
join s in context.SettledTransactions on
new { a = t.Client_Code, b = t.tx_no }
Equals new { a = s.client_code, b = s.tx_no.Value } into g
from ts in g.DefaultIfEmpty()
Select new { t.tx_no, slid= (int?)ts.slid };
LINQ with Lambda Expression var selectlist = context.Transactions.Where(t => t.Client_Code == "CL0011")
.GroupJoin(context.SettledTransactions,
t => new { a = t.Client_Code, b = t.tx_no },
s => new { a = s.client_code, b = s.tx_no.Value },
(t, s) => new { tx = t, sl = s })
.SelectMany(g => g.sl.DefaultIfEmpty(), (g, sl) =>
new { g.tx.tx_no, slid=(int?) sl.slid });
Note In LINQ statement,left join also uses the 'join' keyword. But it groups the data using the 'into' keyword and filter the group with 'DefaultIfEmpty()' method. 'Value' to be used to compare the 'Nullable' fields.
14 Left Join and selecting the records not in 2nd Table
SQL Statement select t.tx_no,s.slid from Transactions t
left join SettledTransactions s
on t.Client_Code= s.client_code and t.tx_no=s.tx_no
where t.Client_Code='CL0011' and slid is null
LINQ Statement var selectlist = from t in context.Transactions
where t.Client_Code == "CL0011"
join s in context.SettledTransactions
on new { a = t.Client_Code, b = t.tx_no }
equals new { a = s.client_code, b = s.tx_no.Value } into g
from ts in g.DefaultIfEmpty()
where ts.slid.HasValue==false
Select new { t.tx_no, slid = (int?)ts.slid };
LINQ with Lambda Expression var selectlist = context.Transactions.Where(t => t.Client_Code == "CL0011")
.GroupJoin(context.SettledTransactions,
t => new { a = t.Client_Code, b = t.tx_no },
s => new { a = s.client_code, b = s.tx_no.Value },
(t, s) => new { tx = t, sl = s })
.SelectMany(g => g.sl.DefaultIfEmpty(), (g, sl) =>
New { g.tx.tx_no, slid = (int?)sl.slid })
.Where(x => x.slid.HasValue==false);
Note Used 'HasValue' to check the slid is NULL
15 Inner + Left Join
SQL Statement select t.tx_no,s.slid,c.client_name from Transactions t
inner join ClientMaster c on t.Client_Code=c.client_code
left join SettledTransactions s
on t.Client_Code= s.client_code and t.tx_no=s.tx_no
where t.Client_Code='CL0011' and slid is null
LINQ Statement var selectlist = from t in context.Transactions
join c in context.ClientMaster on t.Client_Code equals c.client_code
where c.client_code == "CL0011"
join s in context.SettledTransactions on
new { a = t.Client_Code, b = t.tx_no } equals
New { a = s.client_code, b = s.tx_no.Value } into g
from ts in g.DefaultIfEmpty()
select new { t.tx_no, c.client_name, slid = (int?)ts.slid };
LINQ with Lambda Expression var selectlist = context.Transactions
.Join(
context.ClientMaster.Where(x => x.client_code == "CL0011"),
t => t.Client_Code,
c => c.client_code,
(t, c) => new { t, c }
)
.GroupJoin(
context.SettledTransactions,
t => new { a = t.t.Client_Code, b = t.t.tx_no },
s => new { a = s.client_code, b = s.tx_no.Value },
(t, s) => new { t, s }
)
.SelectMany(
g => g.s.DefaultIfEmpty(),
(g, s) => new { g.t.t.tx_no, g.t.c.client_name, slid = (int?)s.slid }
);

**'context' is the Entity Framework context object


Wednesday, January 22, 2014

SQL for XML


Today I went through the sql statements for XML. Here I am sharing the same as a reference

Table to XML
----------------
Creating XML from a TABLE using SELECT statement is very simple in SQL Server 2008. We can form two types of XML from T-SQL statements

1. Each row as element and column values as attributes

SQL

 use Northwind  
 GO  
 select * from Customers as customer where CustomerID in ('ALFKI','ANATR')  
 for xml auto, root('customers')  
 GO  

RESULT

 <customers>  
  <customer CustomerID="ALFKI" CompanyName="Alfreds Futterkiste" ContactName="Maria Anders" ContactTitle="Sales Representative" Address="Obere Str. 57" City="Berlin" PostalCode="12209" Country="Germany" Phone="030-0074321" Fax="030-0076545" />  
  <customer CustomerID="ANATR" CompanyName="Ana Trujillo Emparedados y helados" ContactName="Ana Trujillo" ContactTitle="Owner" Address="Avda. de la Constitución 2222" City="México D.F." PostalCode="05021" Country="Mexico" Phone="(5) 555-4729" Fax="(5) 555-3745" />  
 </customers>  

2. Each row as parent node and column values as child nodes

SQL

 use Northwind  
 GO  
 select * from Customers where CustomerID in ('ALFKI','ANATR')  
 for xml path('customer') ,root('customers')  
 GO  

RESULT

 <customers>  
  <customer>  
   <CustomerID>ALFKI</CustomerID>  
   <CompanyName>Alfreds Futterkiste</CompanyName>  
   <ContactName>Maria Anders</ContactName>  
   <ContactTitle>Sales Representative</ContactTitle>  
   <Address>Obere Str. 57</Address>  
   <City>Berlin</City>  
   <PostalCode>12209</PostalCode>  
   <Country>Germany</Country>  
   <Phone>030-0074321</Phone>  
   <Fax>030-0076545</Fax>  
  </customer>  
  <customer>  
   <CustomerID>ANATR</CustomerID>  
   <CompanyName>Ana Trujillo Emparedados y helados</CompanyName>  
   <ContactName>Ana Trujillo</ContactName>  
   <ContactTitle>Owner</ContactTitle>  
   <Address>Avda. de la Constitución 2222</Address>  
   <City>México D.F.</City>  
   <PostalCode>05021</PostalCode>  
   <Country>Mexico</Country>  
   <Phone>(5) 555-4729</Phone>  
   <Fax>(5) 555-3745</Fax>  
  </customer>  
 </customers>  

In the above sql, if we does not specify the path name - 'customer' in this example,
SQL server will return <row> as the parent element. The SQL statement will go like this

 select * from Customers where CustomerID in ('ALFKI','ANATR')  
 for xml path ,root('customers')  


XML to Table
--------------
In order to convert XML data to Table records we have to get store the XML data in a variable

1. Each row as element and column values as attributes


SQL
 use Northwind  
 GO  
 declare @xml as xml  
 set @xml= (select CustomerID,CompanyName,ContactName,ContactTitle,Address,City   
 from Customers as customer   
 where CustomerID in ('ALFKI','ANATR')  
 for xml auto, root('customers'))  
 SELECT   
     Tbl.Col.value('@CustomerID', 'nchar(10)') CUSTID,   
     Tbl.Col.value('@CompanyName', 'nvarchar(80)') COMPNAME,   
     Tbl.Col.value('@ContactName', 'nvarchar(60)') CONTNAME,   
     Tbl.Col.value('@ContactTitle','nvarchar(60)') CONTTITLE,  
     Tbl.Col.value('@Address', 'nvarchar(120)') ADDRESS,  
     Tbl.Col.value('@City', 'nvarchar(30)') CITY  
 FROM  @xml.nodes('//customers/customer') Tbl(Col)   
 GO  

RESULT

 CUSTID          COMPNAME                    CONTNAME          CONTTITLE          ADDRESS          CITY  
 -----------------------------------------------------------------------------------------------------------------------------------  
 ALFKI        Alfreds Futterkiste               Maria Anders          Sales Representative     Obere Str. 57     Berlin  
 ANATR        Ana Trujillo Emparedados y helados     Ana Trujillo          Owner Avda. de la Constitución 2222     México D.F.  

2. Each row as parent node and column values as child nodes

SQL

 use Northwind  
 GO  
 declare @xml as xml  
 set @xml= (select CustomerID,CompanyName,ContactName,ContactTitle,Address,City   
 from Customers   
 where CustomerID in ('ALFKI','ANATR')  
 for xml path('customer'), root('customers'))  
 SELECT   
     Tbl.Col.value('CustomerID[1]', 'nchar(10)') CUSTID,   
     Tbl.Col.value('CompanyName[1]', 'nvarchar(80)') COMPNAME,   
     Tbl.Col.value('ContactName[1]', 'nvarchar(60)') CONTNAME,   
     Tbl.Col.value('ContactTitle[1]','nvarchar(60)') CONTTITLE,  
     Tbl.Col.value('Address[1]', 'nvarchar(120)') ADDRESS,  
     Tbl.Col.value('City[1]', 'nvarchar(30)') CITY  
 FROM  @xml.nodes('//customers/customer') Tbl(Col)   
 GO  

RESULT

 CUSTID          COMPNAME                    CONTNAME          CONTTITLE          ADDRESS          CITY  
 -----------------------------------------------------------------------------------------------------------------------------------  
 ALFKI        Alfreds Futterkiste               Maria Anders          Sales Representative     Obere Str. 57     Berlin  
 ANATR        Ana Trujillo Emparedados y helados     Ana Trujillo          Owner Avda. de la Constitución 2222     México D.F.  


COLUMN VALUES AS COMMA SEPARATED STRING
----------------------------------------------------------------
One of the interesting thing in SQL for XML is with single line of code we can convert all the values in a table column to a comma separated string
SQL
 use Northwind  
 GO  
 select stuff((select ','+ customerid from Customers for xml path('')),1,1,'') as columnvalues  
 GO  

RESULT
 ALFKI,ANATR,ANTON,AROUT,BERGS,BLAUS,BLONP,BOLID,BONAP,BSBEV,CACTU,CENTC,CHOPS,CONSH,DRACD,DUMON,EASTC,ERNSH,FISSA,FOLIG,FOLKO,FRANK,FRANR,FRANS,FURIB,GALED,GODOS,KOENE,LACOR,LAMAI,LEHMS,MAGAA,MAISD,MORGK,NORTS,OCEAN,OTTIK,PARIS,PERIC,PICCO,PRINI,QUICK,RANCH,REGGC,RICSU,ROMEY,SANTG,SEVES,SIMOB,SPECD,SUPRD,TOMSP,TORTU,VAFFE,VICTE,VINET,WANDK,WARTH,WILMK,WOLZA,OLDWO,BOTTM,LAUGB,LETSS,HUNGO,GROSR,SAVEA,ISLAT,LILAS,THECR,RATTC,LINOD,GREAL,HUNGC,LONEP,THEBI,MEREP,HANAR,QUEDE,RICAR,COMMI,FAMIA,GOURL,QUEEN,TRADH,WELLI,HILAA,LAZYK,TRAIH,WHITC,SPLIR  

Some more references
  1. Update data in the table using XML string
  2. XQuery in SQL Server, some examples

Wednesday, October 30, 2013

Test Driven Development - Part V - Dealing External Dependency with Mock

As I mentioned in the previous session, Stubs are used to test the logic of the class under test  without considering how the dependant objects interact with thc class under test. Some times we need to test how the class under test interacts with the dependant objects or we need to make sure that the class under test interacts correctly with the dependant objects. Mocks are being used in this scenario. So by using Mocks, we are testing wheather the class under test has interacted correctly with the dependant object by verifying the Mock object.


Consider a scenario like the FileUpload class is logging the errors  and whenever an exception happens to the logging, it will mail the exception to the given mail address. Here we are using two dependent classes. One is for logging the errors and one for mailing the exception. If you want to test whether the mails are sending correctly for the exceptions we have to check the mail service object. For that we have to use the  Mock. A stub can be applied for Log service object. The below code shows how to implement it.

1. LogService Interface

 using System;  
 using System.Collections.Generic;  
 using System.Linq;  
 using System.Text;  
 namespace ManualMock_TDD  
 {  
   public interface ILogService  
   {  
     void WriteLog(string logmessage);  
   }  
 }  

2. MailService Interface

 using System;  
 using System.Collections.Generic;  
 using System.Linq;  
 using System.Text;  
 namespace ManualMock_TDD  
 {  
   public interface IEmailService  
   {  
     void SendEmail(string To, string Subject, string Body);  
   }  
 }  

3. The FileUpload Class

 using System;  
 using System.Collections.Generic;  
 using System.Linq;  
 using System.Text;  
 using System.IO;  
 using ManualMock_TDD;  
 namespace Simple_TDD  
 {  
   public class FileUpload  
   {  
     private ILogService _LogService;  
     private IEmailService _Email;  
     public ILogService LogService  
     {  
       get { return _LogService; }  
       set { _LogService = value; }  
     }  
     public IEmailService EmailService {  
       get {return _Email ;}  
       set {_Email=value ;}  
     }  
     public void ValidateFilename(string filename)   
     {  
       //return ValidateObj.IsValid(filename);  
       if (filename.Length < 8)  
       {  
         try  
         {  
           LogService.WriteLog("file name is too short");  
         }  
         catch (Exception ex)  
         {  
           EmailService.SendEmail("mail@me.com", "Error occured while writing log", ex.Message);   
         }  
       }  
     }  
   }  
 }  

4. The Unit Test Class

 using Simple_TDD;  
 using Microsoft.VisualStudio.TestTools.UnitTesting;  
 using System;  
 namespace ManualMock_TDD.Tests  
 {  
   [TestClass()]  
   public class FileUploadTest  
   {  
     [TestMethod]  
     public void ValidateFilename_EmptyFileName_WillSendEmail()  
     {  
       StubLogService logservice = new StubLogService();  
       logservice.ToThrow = new Exception("filename to short");  
       MockEmailService eMailService = new MockEmailService();  
       FileUpload Target = new FileUpload();  
       Target.LogService = logservice;  
       Target.EmailService = eMailService;  
       Target.ValidateFilename("abc.txt");  
       Assert.AreEqual("mail@me.com", eMailService.To);  
       Assert.AreEqual("Error occured while writing log", eMailService.Subject);  
       Assert.AreEqual("filename too short", eMailService.Body);  
     }  
   }  
   class StubLogService : ILogService  
   {  
     public Exception ToThrow;  
     public void WriteLog(string msg)  
     {  
       throw ToThrow;  
     }  
   }  
   class MockEmailService : IEmailService  
   {  
     public string To;  
     public string Subject;  
     public string Body;  
     public void SendEmail(string to,string subject,string body)  
     {  
       To = to;  
       Subject = subject;  
       Body = body;  
     }  
   }  
 }  


In the example, the FileUpload class is using two interface objects. One for log service and another for email service.  For unit testing we use stub for  Log Service and mock object for Email. We need mock object for email here because we are going to check the content of the mail sent by the FileUpload class. To generate the scenario, the StubLogService will throw an exception. Then the FileUpload class will  call the mail service and will send the exception to the address given. The assertions will be done on the mail object. The last three lines in the test method is verifying the mail object to ensure about the exception handled in the  FileUpload class

Monday, October 28, 2013

Test Driven Development - Part IV - Dealing with External Dependency using Stub

An external dependency is an object in your system that your code under test interacts with, and over which you have no control. (Common examples are filesystems, threads, memory, time, and so on.). Mocks and Stubs are used to deal with external dependency. Both are fake objects to represent external dependent objects.Before going deep into mock and stub, we have to know how to refactor our code to apply mocks and stubs. Refactoring is the act of changing the code’s design without breaking existing functionality.

Consider our file upload class we used in the previous session. Assume that we have a file stored in the filesystem which consist of the rules related to the validation. The file upload class will have to validate the file name against the rules in the file. In this case, there we have a Validate class which deals with the accessing the file and validating the file name.   This Validate class is the dependency class of File upload class.
In order to break the dependency, we have to add one more layer of indirection. It can be either an Abstract Class or an Interface. Both have its own advantages and disadvantages. Here I am using Interface as the layer of indirection. So we have to do the following
  1. Extract an interface to allow replacing underlying implementation.
  2. Receive an interface at the constructor level or as a property.
After refactoring our code to a loosely coupled architeture, we can easily inject mock or stub into the application for the purpose of testing

STUB


Stub is a fake object the class under test has depended on. Stubs are used to by pass an external dependency. If a class is having external dependency, the unit test will fail when the dependency fails even if the logic in the Class Under Test is correct. Stubs are used to overcome this kind of issues. The unit test will test the class under test and during the process the Class Under Test will call the Stub class  instead of  calling the real external dependent object which will return the expected result to the class under test. The assertion is done with the class under test.

Example

IValidate Interface
 using System;  
 using System.Collections.Generic;  
 using System.Linq;  
 using System.Text;  
 namespace ManualStub_TDD  
 {  
   public interface IValidate  
   {  
     bool IsValid(string Filname);  
   }  
 }  

FileUpload class

 using System;  
 using System.Collections.Generic;  
 using System.Linq;  
 using System.Text;  
 using System.IO;  
 using ManualStub_TDD;  
 namespace Simple_TDD  
 {  
   public class FileUpload  
   {  
     private IValidate ValidateObj;  
     public IValidate ValidationObj {   
       get{return ValidateObj;}  
       set { ValidateObj = value; }  
     }  
     public bool ValidateFilename(string filename)   
     {  
       return ValidateObj.IsValid(filename);  
     }  
   }  
 }  

Unit Testing project
 using Simple_TDD;  
 using Microsoft.VisualStudio.TestTools.UnitTesting;  
 using System;  
 using ManualStub_TDD;  
 namespace ManualStub.Tests  
 {  
   [TestClass()]  
   public class FileUploadTest  
   {  
     [TestMethod]  
     public void ValidateFileName_FilenameShorterThan6Letters_ReturnsFalse()  
     {  
       ValidateStub Vstub = new ValidateStub();  
       Vstub.StubReturnValue = false;  
       FileUpload target = new FileUpload();  
       target.ValidationObj = Vstub;  
       bool actual = target.ValidateFilename("abc.txt");  
       Assert.AreEqual(false, actual, "Method Allows shorter filenames");  
     }  
   }  
 }  
  class ValidateStub : IValidate  
 {  
   public bool StubReturnValue;  
   public bool IsValid(string filename)  
   {  
     return StubReturnValue;  
   }  
 }  


Here there is an IValidate interface and it contain the IsValid method. The Validate class will implement the IValidate interface. The "ValidationObj" prpoerty in the FileUpload class  will hold instance of classes implementing Ivalidate interface.  The ValidateFilename method will use this property to validate the file name and will return the boolean result.

For the purpose of unit testing, an internal stub class is created which implements the Ivalidate interface. To control the output, one more property has been added to the class. The stub will be initialized  in the Test Method. And that stub will be passed to the Target as property. And the method will evaluate the class under test.

Wednesday, May 15, 2013

Test Driven Development - Part III - Microsoft Testing Tools

Microsoft has also developed their own testing tools. Since VS2005, It has been integrated with the IDE. One of the main advantage of using Microsoft testing tool is the debugging feature with it. But it is not a standalone application. So you need to open the project whenever you want to run the tests.

We can start by opening the same project we did in the previous example.
Add new project to the solution by selecting File => Add => New Project => Visual C# => Test => Unit Test Project.(In VS2010 we had an option to create unit test project by right clicking on the method and selecting 'Create Unit Tests...'  from the popup menu. In VS2012 that feature has been dropped.)

Enter the Name "TddwithNunit.Tests2" and press OK button
The Project will be added to the solution. The project will be referenced to "Microsoft.VisualStudio.QualityTools.UnitTestFramework " and the project will have the following code.

 using System;  
 using Microsoft.VisualStudio.TestTools.UnitTesting;  
 namespace TddwithNunit.Tests2  
 {  
   [TestClass]  
   public class UnitTest1  
   {  
     [TestMethod]  
     public void TestMethod1()  
     {  
     }  
   }  
 }  

Unlike Nunit, Microsoft uses [TestClass] and [TestMethod] attributes for Class and Methods respectively. Add reference to the TddwithNunit project. Rename the class file to "FileUploadTests" and modify the code as below.

 using System;  
 using Microsoft.VisualStudio.TestTools.UnitTesting;  
 namespace TddwithNunit.Tests2  
 {  
   [TestClass]  
   public class FileUploadTests  
   {  
     [TestMethod]  
     public void ValidateFileName_FilnameShorterthan6letters_ReturnsFalse()  
     {  
       //Assign  
       fileupload file = new fileupload();  
       //Act  
       var result = file.ValidateFileName("abc.txt");  
       //Assert  
       Assert.IsFalse(result, "Shorter Filenames are returning true");  
     }  
   }  
 }  


Now build the solution.

Select => Test =>Run =>All Tests . The result of the test will be displayed in Test Explorer inside the IDE as below.


The test has been failed. This logic has not been implemented into the ValidateFilename method. We have to refactor the code as below

 public class fileupload  
   {  
     public bool ValidateFileName(string filename)  
     {  
       bool returnvalue = false;  
       if (filename != string.Empty)  
       {  
         var filepart1 = filename.Split('.').First();  
         if (filepart1.Length >= 6)  
           returnvalue = true;  
       }  
       return returnvalue;  
     }  
   }  
 }  

And run the Test again from the Test Explorer => Run All


The test has been succeeded this time.

Wednesday, May 1, 2013

Test Driven Development - Part II - Working with NUnit


NUnit is a popular unit-testing framework for all .Net languages. It is xUnit based unit testing tool for Microsoft .NET. xUnit is a collection unit testing frameworks which  provides an automated solution with no need to write the same tests many times, and no need to remember what should be the result of each test

xUint is originally develped by Kent Beck. , the brain behind test driven development.

NUnit is an open source testing tool. It can be downloaded from www.NUnit.org  It is a stand alone application. So we can run the test any time without opening the Visual Studio Project.

Here is an simple example of doing a TDD in Visual Studio with NUnit

Open Visual Studio 2010/2012
Select File => New Project => Visual C# => Console Application
Enter Project Name 'TDDWithNunit' and press OK button
Add a class with name 'fileupload' to the project
Add the following code to the class


 public class fileupload  
   {  
     public bool ValidateFileName(string filename)  
     {  
       throw new NotImplementedException();  
     }  
   }  


Now we are about to start the coding for 'ValidateFileName'. But in test driven development, we have to write the unit test before writing actual development code. The above code is just enough to compile the project.

Add new project to the solution by selecting File => Add => New Project => Visual C# => Class Library
Enter the Project Name ' TDDWithNunit.Tests'
Rename the Class1.cs to "fileuploadTests.cs"

For each class we have to create corresponding unit testing class. For the readability it would be better to give the test class name as "<Class Under Test Name>Tests"

We need to add reference to the project under test to the unit testing project.  Right click References  and select Solution => Project => TddwithNUnit.

Add NUnit framework reference to the project from Assemblies => Extensions =>nunit.framework
Add the following code to the Test class.
 using System;  
 using System.Collections.Generic;  
 using System.Linq;  
 using System.Text;  
 using System.Threading.Tasks;  
 using NUnit.Framework;  
 namespace TddwithNunit.Tests  
 {  
   [TestFixture]  
   public class fileuploadTests  
   {  
     [Test]  
     public void ValidateFileName_EmptyFilname_ReturnsFalse()  
     {  
       //Assign  
       fileupload file = new fileupload();  
       //Act  
       var result =file.ValidateFileName("");  
       //Assert  
       Assert.IsFalse(result, "Filename allows empty string");  
     }  
   }  
 }  

In the above code, [TestFixture] attribute has been added to the class and [Test] attribute has added to the testing method as well. This two attributes are required for the Nunit framework to detect the test class and methods. Naming of methods also need some attention. It should be "Public" and "void". It will be better to name the testing method in manner like __. It will help to find the issue easily even the method contains more number of methods. Now build the application. Load Nunit from the Start Menu Select File => Open Project =>\bin\Debug\ TddwithNunit.Test.dll





It will display the test class and method as in the above image Click the Run button


The method will fail because the method is not implemented. It will be indicated by the red line. Now modify the ValidateFileName method as below

  public bool ValidateFileName(string filename)  
     {  
       //throw new NotImplementedException();  
       if (filename != string.Empty)  
       {  
         return true;  
       }  
       else { return false; }  
     }  

Build the Application Run the NUnit Application. It will load the project automatically
Click the Run button

The test passed this time with the green signal. We can refactor the code now.