Wednesday, May 31, 2006

Important Marc Clifton Testing Types/Patterns

Introduction
The next version of Microsoft's Visual Studio will include tools to automate refactoring.  Tools that automate unit test generation would address some of the issues concerning maintenance and cost.
However, to achieve this acceptance, unit testing must be formalized so that it becomes a real engineering discipline rather than an ad hoc approach that relies on the capabilities of the programmer.  Many people balk at the idea of writing the unit test first--it places them in the uncomfortable position of having to do up front design work.
There is no formal unit test engineering discipline. 
Two things are needed--a formalization of unit testing by establishing unit test patterns, and the early adoption of object oriented design patterns in the developing application to specifically target the needs of unit testing. 
One of the goals is a tool suite that can automatically generate unit tests, both as a reverse and forward engineering process.  With the latter, it should be possible to generate the method stubs for the code under test. 
Patterns
The patterns that I have identified so far can be loosely categorized as:
pass/fail patterns
collection management patterns
data driven patterns
performance patterns
process patterns
simulation patterns
multithreading patterns
stress test patterns
These are broad brush strokes. 
Pass/Fail Patterns
These patterns are deceptive in what they tell you about the code.
The Simple-Test Pattern [yes]
When a unit test passes a simple test, all it does is tell me that the code under test will work if I give it exactly the same input as the unit test.  A unit test that exercises an error trap is similar--it only tells me that, given the same condition as the unit test, the code will correctly trap the error.  In both cases, I have no confidence that the code will work correctly with any other set of conditions, nor that it will correctly trap errors under any other error conditions.  This really just basic logic.  However, on these grounds you can hear a lot of people shouting "it passed!" as all the nodes on the unit test tree turn green.
The Parameter-Range Pattern [Yes]
The Parameter-Range pattern does this by feeding the Code-Path pattern with more than a single parameter set.
Data Driven Test Patterns
Constructing Parameter-Range unit tests is doable for certain kinds of testing, but it becomes inefficient and complicated to test at a piece of code with a complex set of permutations generated by the unit test itself.  The data driven test patterns reduce this complexity by separating the test data from the test.  The test data can now be generated (which in itself might be a time consuming task) and modified independent of the test.
The Simple-Test-Data Pattern
In the simplest case, a set of test data is iterated through to test the code and a straightforward result (either pass or fail) is expected.  Computing the result can be done in the unit test itself or can be supplied with the data set.  Variances in the result are not permitted.  Examples of this kind of of Simple-Test-Data pattern include checksum calculations, mathematical algorithms, and simple business math calculations.  More complex examples include encryption algorithms and lossless encoding or compression algorithms.
The Data-Transformation-Test Pattern
Data Transaction Patterns
Data transaction patterns are a start at embracing the issues of data persistence and communication.  More on this topic is discussed under "Simulation Patterns".  Also, these patterns intentionally omit stress testing, for example, loading on the server.  This will be discussed under "Stress-Test Patterns".
The Simple-Data-I/O Pattern

This is a simple data transaction pattern, doing little more than verifying the read/write functions of the service.  It may be coupled with the Simple-Test-Data pattern so that a set of data can be handed to the service and read back, making the transaction tests a little bit more robust.
The Constraint-Data Pattern

The Constraint-Data pattern adds robustness to the Simple-Data-I/O pattern by testing more aspects of the service and any rules that the service may incorporate.  Constraints typically include:
can be null
must be unique
default value
foreign key relationship
cascade on update
cascade on delete
As the diagram illustrates, these constraints are modeled after those typically found in a database service and are "write" oriented.  This unit test is really oriented in verifying the service implementation itself, whether a DB schema, web service, or other model that uses constraints to improve the integrity of the data.
The Rollback Pattern

The rollback pattern is an adjunct to the other transaction testing patterns.  While unit tests are supposed to be executed without regard to order, this poses a problem when working with a database or other persistent storage service.  One unit test may alter the dataset causing another unit test to inappropriately fail.  Most transactional unit tests should incorporate the ability to rollback the dataset to a known state.  This may also require setting the dataset into a known state at the beginning of the unit test.  For performance reasons, it is probably better to configure the dataset to a known state at the beginning of the test suite rather than in each test and use the service's rollback function to restore that state for each test (assuming the service provides rollback capability).
Collection Management Patterns
A lot of what applications do is manage collections of information.  While there are a variety of collections available to the programmer, it is important to verify (and thus document) that the code is using the correct collection.  This affects ordering and constraints.
The Collection-Order Pattern

This is a simple pattern that verifies the expected results when given an unordered list.  The test validates that the result is as expected:
unordered
ordered
same sequence as input
This provides the implementer with crucial information as to how the container is expected to manage the collection.
The Collection-Constraint Pattern

This pattern verifies that the container handles constraint violations: null values and inserting duplicate keys.  This pattern typically applies only to key-value pair collections.
The Collection-Indexing Pattern

The indexing tests verify and document the indexing methods that the collection container must support--by index and/or by key.  In addition, they verify that update and delete transactions that utilize indexing are working properly and are protected against missing indexes.
Performance Patterns
Unit testing should not just be concerned with function but also with form.  How efficiently does the code under test perform its function?  How fast?  How much memory does it use?  Does it trade off data insertion for data retrieval effectively?  Does it free up resources correctly?  These are all things that are under the purview of unit testing.  By including performance patterns in the unit test, the implementer has a goal to reach, which results in better code, a better application, and a happier customer.
Process Patterns
The Process-Sequence Pattern
This pattern verifies the expected behavior when the code is performed in sequence, and it validates that problems when code is executed out of sequence are properly trapped.  The Process-Sequence pattern also applies to the Data-Transaction pattern--rather than forcing a rollback, resetting the dataset, or loading in a completely new dataset, a process can build on the work of the previous step, improving performance and maintainability of the unit test structure.
Simulation Patterns
Mock objects can come to the rescue by simulating the database, web service, user event, connection, and/or hardware with which the code is transacting.  Mock objects also have the ability to create failure conditions that are very difficult to reproduce in the real world--a lossy connection, a slow server, a failed network hub, etc.  However, to properly use mock objects the code must make use of certain factory patterns to instantiate the correct instance--either the real thing or the simulation.  All too often I have seen code that creates a database connection and fires off an SQL statement to a database, all embedded in the presentation or business layer!  This kind of code makes it impossible to simulate without all the supporting systems--a preconfigured database, a database server, a connection to the database, etc.  Furthermore, testing the result of the data transaction requires another transaction, creating another failure point.  As much as possible, a unit test should not in itself be subject to failures outside of the code it is trying to test.
Mock-Object Pattern
In order to properly use mock objects, a factory pattern must be used to instantiate the service connection, and a base class must be used so that all interactions with the service can be managed using virtual methods.  (Yes, alternatively, Aspect Oriented Programming practices can be used to establish a pointcut, but AOP is not available in many languages). 
To achieve this construct, a certain amount of foresight and discipline is needed in the coding process.  Classes need to be abstracted, objects must be constructed in factories rather than directly instantiated in code, facades and bridges need to be used to support abstraction, and data transactions need to be extracted from the presentation and business layers.  These are good programming practices to begin with and result in a more flexible and modular implementation. 
The Service-Simulation Pattern

This test simulates the connection and I/O methods of a service.  In addition to simulating an existing service, this pattern is useful when developing large applications in which functional pieces are yet to be implemented.
The Bit-Error-Simulation Pattern

I have only used this pattern in limited applications such as simulating bit errors induced by rain-fade in satellite communications.  However, it is important to at least consider where errors are going to be handled in the data stream--are they handled by the transport layer or by higher level code?  If you're writing a transport layer, then this is a very relevant test pattern.
The Component-Simulation Pattern

In this pattern, the mock object simulates a component failure, such as a network cable, hub, or other device.  After a suitable time, the mock object can do a variety of things:
throw an exception
return incomplete or completely missing data
return a "timeout' error
Again, this unit test documents that the code under test needs to handle these conditions.
Presentation Layer Patterns

Thursday, May 25, 2006

CSharp log parsing file

//Jonathan Mark
//NG Midtier Team
//May 2006
//Application for reading customized log files.

//The application looks for phrases which indicate that a processor is entering a period
// of inactivity. The next timed log entry after such a shutdown is a startup.

// Line 3114 of allergy_060514 is out of order. A later time appears before an earlier one.

//This degenerate log condition interferes with the logic of the application, which
// assumes that each row occurred at or after the time of the row above it.

// Sorting files with potentially hundreds of thousands of rows in a client .NET application
// could be impractical. Therefore, this application first checks to make certain that the log
// is sorted. If not it stops processing and alerts the user to sort the file.

// File allergy_060513 has corrupted dates which begin with the numerals 00. These need to be
//removed prior to sorting. If not the application stops processing and alerts the user to
// sort the file.

using System;
using System.Collections;
using System.IO;
using System.Reflection;
using MbUnit.Core;
using MbUnit.Framework;
using System.Text.RegularExpressions;



[TestFixture]
class ParseLog
{


public TimeSpan totalOnTime = (DateTime.Now - DateTime.Now);
public TimeSpan totalOffTime = (DateTime.Now - DateTime.Now);
string myLine = "";
int iMonth;
int iDay;
int iYear;
int iHour;
int iMinute;
int iSec;
public DateTime lastStart;
public DateTime lastFinish;
int numberOfStarts = 0;

public ParseLog()
{
Console.WriteLine("Starting Processing...");
}


[Test] public DateTime ConvertToDate(string snippet)
// i is the row of the file being processed. Currently only used for debugging.
{
//use of offsets deprecated
if (snippet.Substring(3,1) == "/") // Some dates are corrupted and
// have an extra zero in front.
{
//This is a corrupt row, as its month numeral has three digits
Assert.AreEqual(1,0, "The input file has a corrupt date that starts with an extra zero.");
}
DateTime dtInSnippet;
iMonth = Int32.Parse(snippet.Substring(0, 2));
iDay = Int32.Parse(snippet.Substring(3, 2));
iYear = Int32.Parse(snippet.Substring(6, 4 ));
iHour = Int32.Parse(snippet.Substring(11, 2 ));
iMinute= Int32.Parse(snippet.Substring(14, 2 ));
iSec = Int32.Parse(snippet.Substring(17, 2 ));
dtInSnippet=new DateTime(iYear,iMonth,iDay,iHour,iMinute,iSec);
return dtInSnippet;
}



public bool IsFinished(string strFinished)
//Tests for phrases indicating Processor is shutting down
{
Regex objNotWholePattern1=new Regex("Finished processing");
if(objNotWholePattern1.IsMatch(strFinished))
{
lastFinish = ConvertToDate(strFinished);
TimeSpan recentInterval = lastFinish - lastStart;
totalOnTime = totalOnTime + recentInterval;
numberOfStarts = 0;
}
else
{
Regex objNotWholePattern2=new Regex("Starting processing");
if ((IsADate(strFinished)) & (numberOfStarts == 0) & objNotWholePattern2.IsMatch(strFinished))
{
lastStart = ConvertToDate(strFinished);
numberOfStarts = 1;
}

}
return objNotWholePattern1.IsMatch(strFinished);
}








public bool IsADate(string strIsADate)
{
Regex objNotWholePattern3=new Regex("^[0-9][0-9]");

return objNotWholePattern3.IsMatch(strIsADate);
}




[Test] void readLog(String filename)
{


Console.WriteLine("Reading File...");
StreamReader srRead = File.OpenText(filename);
srRead.BaseStream.Seek(0, SeekOrigin.Begin);

while (srRead.Peek() > -1)
{
myLine = srRead.ReadLine() + "\n";
myLine = myLine.Trim();
if (IsFinished(myLine))
{
Console.WriteLine(myLine + totalOnTime.ToString());
}

}
srRead.Close();
Console.WriteLine("Finished reading File...");
}




///
/// Summary description for Class1.
///

class Class1
{
///
/// The main entry point for the application.
///

[STAThread]

static void Main(string[] args)
{
ParseLog myParseLog = new ParseLog();
myParseLog.readLog("c:\\logs\\allergy_060513.log");
Console.WriteLine(myParseLog.totalOnTime.ToString());
int x = 1;
while (x == 1)
{
x = 1;
}

}
}

}

Wednesday, May 24, 2006

Advice on DTML

dtml is fine - _if_ you stick to dtml-if, dtml-in and dtml-var!

Tuesday, May 23, 2006

Lessons Learned From C# Log Parsing File

(1) To check for the existence of a file be sure to prefix System.IO:

Image1.Visible = System.IO.File.Exists(imagePath);

(2) For Loops are as follows:


for (int a =0; a<5;>

2.

{

3.

System.Console.WriteLine(a);

4.

}



(3) Read a file and split it up as an array as follows:


//variable "myFile"
StreamReader srRead = File.OpenText(fileName);
srRead.BaseStream.Seek(0, SeekOrigin.Begin);

while (srRead.Peek() > -1)
{
myFile = myFile + srRead.ReadLine() + "\n";
}

//Close the file
srRead.Close();

//Split the file into an array
//using a newline character as the split character
char[] splitChar = {'\n'};
string [] fileArray;
fileArray = myFile.Split(splitChar);
(4) Create a member function that tests using regex's as follows:

 // Function to test for Positive Integers with zero inclusive

public bool IsWholeNumber(string strNumber)
{
Regex objNotWholePattern=new Regex("[^0-9]");

return !objNotWholePattern.IsMatch(strNumber);


(5) DateTimes are as follows. Make certain to use the correct parameter order. It is not intuitive:

private DateTime dtDob;
private DateTime dtNow;
private DateTime dtAge;
private int intDay;
private int intMonth;
private int intYear;
private int intHour;
private int intMinute;
private TimeSpan tsAge;
 dtNow=DateTime.Now;
 dtDob=new DateTime(intYear,intMonth,intDay,intHour,intMinute,0);

When you subtract one DateTime from another you get a TimeSpan, not a number.

(5) Slicing a string:


string result = param.Substring(startIndex, length);


(6) Converting a string to an Int:

string myStr = "123";
int myParsedInt = Int32.Parse(myStr);

(7) Object Oriented Hello World


using System;

public class HelloWorld

{

public void helloWorld()

{

Console.WriteLine("HELLO WORLD");

}



public static void Main()

{

HelloWorld hw = new HelloWorld();

hw.HelloWorld();

}

}





(9) Incredibly, in the 1.1 version of C# you cannot test ints and most other objects to see if they are null. You can only test a string. You must therefore create an indicator string that you set to a value whenever you set an int variable to a non-null value. Then you test that string. Unbelievable.

Sunday, May 21, 2006

Possible Error in Boo Implementation of StreamReader

A poster on the Google Boo group responded. The problem was that there were two StreamReader functions, one of which took a Stream as its parameter and one a String. Boo was guessing that I was using the Stream version when in fact I was using the string. The solution was to specify the parameter as


filename as String


I am using a .7 version of Boo and Nunit in SharpDevelop 2 under Windows.

The first of the following two scripts produces an error.

Yet the only difference between the two scripts is that in the error-prone version StreamReader uses a passed string parameter containing the name of the file. The non-error-prone version uses a hard-coded string value. Yet the unit test shows that the values of the hard-coded string and of the passed parameter are the same.

The first script gives me this error:

Exception System.InvalidCastException was thrown in debugee:Unable to cast object of type 'System.String' to type 'System.IO.Stream'.
readLog() - C:\Documents and Settings\Administrator\My Documents\SharpDevelop Projects\ParseLogsBoo\Program.boo:15,0Main() - C:\Documents and Settings\Administrator\My Documents\SharpDevelop Projects\ParseLogsBoo\Program.boo:21,0

The script producing the error is:


namespace ParseLogsBoo
import System
import System.Collections
import System.Xml from System.Xml
import System.IO
import System.Reflection
import NUnit.Framework from "nunit.framework"
[TestFixture]

class ParseLog:
[Test]
....def readLog(filename):
........if File.Exists(filename):
............using input = StreamReader(filename):
................Assert.AreEqual(filename,"c: \\logs\\shortlog.txt")

testfile = "c: \\logs\\shortlog.txt"
myParseLog = ParseLog()
myParseLog.readLog(testfile)




However, the following script runs without error:


namespace ParseLogsBoo
import System
import System.Collections
import System.Xml from System.Xml
import System.IO
import System.Reflection
import NUnit.Framework from "nunit.framework"
[TestFixture]
class ParseLog:

[Test]
....def readLog(filename):

........if File.Exists(filename):
............using input = StreamReader("c: \\logs\\shortlog.txt"):
................Assert.AreEqual(filename,"c: \\logs\\shortlog.txt")

testfile = "c: \\logs\\shortlog.txt"
myParseLog = ParseLog()
myParseLog.readLog(testfile)

Friday, May 19, 2006

Read each line of a file conditionally in Boo

Just for the record, either C# or VB.NET can convert to Boo, but Boo does not convert to either.


namespace ParseLogsBoo

import System
import System.Collections
import System.Xml from System.Xml
import System.IO
import System.Reflection

testfile = "c:\\logs\\shortlog.txt"
if File.Exists(testfile):
print "Found shortlog.txt"




using input = StreamReader(testfile): //or you can use File.OpenText
for line in input:
line = line.Trim()
if line =~ "Starting processing|Finished processing":
print line

Do Not Declare Variables Inside Try Blocks If You Want To Use Them Later

Try
Dim A As Integer = 1
Catch
Dim A As Integer = 2
End Try

A = 1/(A + 1)


Will not Build inside of VS/VB.NET . Instead say

Dim A
Try
A = 1
Catch
A = 2
End Try

A = 1/(A + 1)

Thursday, May 18, 2006

Automatically redirecting notfound errors in Zope

In DTML it is as simple as:






Wednesday, May 17, 2006

Running sql from dos

First of all, there can be problems if there are multiple tnsnames.ora files on a computer. The tnsping command can use one tnsnames.ora file while the sqlplus command can use another. This can cause a Service Name Not Provided error if one of the tnsnames.ora files is missing an entry.

Here is what I use:


sqlplus acpg/acpg@dev143 @c:\tempo.sql



From the SQL*PLUS

To run a command file as you start SQL*Plus, use one of the following four options:
Follow the SQLPLUS command with your username, a slash, your password, a space, @, and the name of the file:
SQLPLUS SCOTT/TIGER @SALES


SQL*Plus starts and runs the command file.
Follow the SQLPLUS command and your username with a space, @, and the name of the file:
SQLPLUS SCOTT @SALES


SQL*Plus prompts you for your password, starts, and runs the command file.
Include your username as the first line of the file. Follow the SQLPLUS command with @ and the filename. SQL*Plus prompts for your password, starts, and runs the file.
Include your username, a slash (/), and your password as the first line of the file. Follow the SQLPLUS command with @ and the filename. SQL*Plus starts and runs the file.

Tuesday, May 16, 2006

How to run a SQL script from the SQL*Plus command line

> @c:\tempo.sql

How To Read An Entire File In VB.NET

Dim EntireFile As String
Dim oFile As System.IO.File
Dim oRead As System.IO.StreamReader
oRead = oFile.OpenText("C:\tempo.txt")
EntireFile = oRead.ReadToEnd()

Sunday, May 14, 2006

There are no default parameters in Boo

From 2006 Boo Google Groups Post:

"Okay. The question is, Why don't we have default parameters? I think
there are a couple of reasons. First of all, they're somewhat
duplicative of overloading. I mean you can do the same with
overloading, and which is indeed what people do today, but yes,
you're right. It's more typing for sure. I

Unit Test in BOO.

"""
Author: Jonathan Mark ,
Program: Boo Language Test File
Date: 2006

Description: This file contains classes for testing
features of the Boo language
"""


namespace BooDatabase
import NUnit.Framework from "nunit.framework"
import System
import System.Collections

import System.Data.OracleClient

[TestFixture]

class testDatabase:
[Test]
def helloWorld():
connectionString = "Data Source=XE;User ID=system;Password=acpg;"
dbcon = OracleConnection(connectionString)
dbcon.Open()
dbcmd = dbcon.CreateCommand()
sql = "SELECT user, 'hello' as myhello from dual"
dbcmd.CommandText = sql
reader = dbcmd.ExecuteReader()
while reader.Read():
nombre = reader["user"]
descripcion = reader["myhello"]
print "Tabla: ${nombre} Descripción: ${descripcion}"
Assert.AreEqual(descripcion,"hello")


x = 1
while x = 1:
x = 1

No Entry Point Found Error In Boo

The following is from the Codehaus Boo Language website

In Boo, every .boo file requires an entry point (a body of statements at the
module level that will be evaluated when the program is executed). And that
entry point must occur only after all of your class, interface, function,
etc. definitions. So,

def CantJustDefineMe():
pass

will raise an exception

BCE0028: Boo.Lang.Compiler.CompilerError: No entry point found.

And

print("You won't see me because this program will raise an exception")
def CantDefineMeHere():
pass

will raise an exception like

test.boo(2,1): BCE0044: Boo.Lang.Compiler.CompilerError: expecting "EOF",
found 'def'. ---> test.boo:2:1: expecting "EOF", found 'def'
--- End of inner exception stack trace ---


Oh, and a .boo file that only contains

pass

,or that contains nothing at all, will also raise a similar exception to the
one above. In Python, none of the above code would raise an exception.


End gotcha.

Thursday, May 11, 2006

Solving Mutating Table Problem

The addition of a transaction, commit and second connection to the above solves the problem of a mutating table due to triggers.

The stored procedures both use the same connection

Public Sub testClass3()
myOraConn2.Open()


Dim myOracleTransaction As OracleTransaction = myOraConn2.BeginTransaction()

testDeactivatePatientFromRegistry() ' creates a new registry_id set to Class variable Rid.

myOracleTransaction.Commit()

myOraConn2.Close()
testDeleteRegistry()
End Sub

)RA-00936 Missing Expression

This error is likely caused by a variable in the VB.NET program being null. When it gets inserted into the SQL string it produces a missing expression error.

Do not use parentheses when callling stored procedures in Oracle and VB.NET

The proper way to call Oracle stored procedures from VB.NET is "REGISTRY_PKG.DELETE_REGISTRY"

Do not call them from with parentheses, e.g., mysp() . It will not run .

Wednesday, May 10, 2006

Connecting to an Oracle XE database inside VB.NET

'cn = New OdbcConnection("DRIVER={Oracle in OraHome81};SERVER=XE;UID=system;" _
' & "PWD=mypass;DBQ=XE;") ' for connection to J. Mark's laptop.

Allowable OraclelDbType values

cmd.Parameters.Add(New OracleParameter("p_result_date", OracleDbType.Date)).Value = Now

The allowable values of OracleDbType are the same as the allowable types in Oracle. Thus you have a Varchar2 value, an Int64 value, etc.

These values differ from those for ODBC connections to Oracle databases

Friday, May 05, 2006

Picking a temporarily unique number in VB.NET

Dim longTime As Long = Now.ToFileTimeUtc()
Dim uniqueID As Integer = longTime Mod 1000000000

Thursday, May 04, 2006

Find Object In Toad

To find an Oracle object using Toad click on the flashlight icon on the main toolbar.

http://www.samspublishing.com/articles/article.asp?p=31544&rl=1

Wednesday, May 03, 2006

How To Run A Stored Procedure That Returns A Ref Cursor And Reat Returned Values

Private Sub PopulateRegistry()


Dim registryID As String
Dim oradb As String = "Data Source=(DESCRIPTION=" _
+ "(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=myhost)(PORT=1521)))" _
+ "(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=PROD.World)));" _
+ "User Id=myid;Password=mypass;"

Dim myConnection As New OracleConnection(oradb)

myConnection.Open()

Dim sql As String = "ACPG_V1_PKG.ADD_REGISTRY"
Dim readMaxRegIDSql As String = "select max( "
Dim cmdAddRegistry As New OracleCommand(sql, myConnection)



'Find out what the next value of ACPG_Registry.

cmdAddRegistry.CommandType() = CommandType.StoredProcedure
cmdAddRegistry.Parameters.Add(New OracleParameter("p_registry_name", OracleDbType.Varchar2)).Value = "1"
cmdAddRegistry.Parameters.Add(New OracleParameter("p_owner_ncid", OracleDbType.Int64)).Value = 1
cmdAddRegistry.Parameters.Add(New OracleParameter("p_owner_type", OracleDbType.Int64)).Value = 1
cmdAddRegistry.Parameters.Add(New OracleParameter("p_status", OracleDbType.Int64)).Value = 1
cmdAddRegistry.Parameters.Add(New OracleParameter("p_restricted_flag", OracleDbType.Char)).Value = "1"
cmdAddRegistry.Parameters.Add(New OracleParameter("p_default_dx_medcin_id", OracleDbType.Int64)).Value = 1
cmdAddRegistry.Parameters.Add(New OracleParameter("p_URL", OracleDbType.Varchar2)).Value = "1"
cmdAddRegistry.Parameters.Add(New OracleParameter("p_created_date", OracleDbType.Date)).Value = Now
cmdAddRegistry.Parameters.Add(New OracleParameter("p_created_by_ncid", OracleDbType.Int64)).Value = 1
Dim prm = New OracleParameter("curVar", OracleDbType.RefCursor, DBNull.Value, ParameterDirection.Output)
cmdAddRegistry.Parameters.Add(prm)


cmdAddRegistry.ExecuteNonQuery()

Dim oraref As OracleRefCursor = cmdAddRegistry.Parameters("curVar").Value

Dim dr As OracleDataReader = oraref.GetDataReader()

Dim RetVal As Integer

dr.Read()

RetVal = dr(0)


Assert.GreaterThan(RetVal, 0)

'Verify that the new row in the ACPG Registry exists

Dim mystringRegistryId As String = "SELECT MAX(Registry_ID) as maxID from acpg_registry R"

Dim cmdCheckRegistry As New OracleCommand(mystringRegistryId, myConnection)





Dim Ridds As New DataSet
Dim Ridda As OracleDataAdapter
Dim Riddt As DataTable
Ridda = New OracleDataAdapter(cmdCheckRegistry)
Ridda.Fill(Ridds, "R")
Riddt = Ridds.Tables("R")

Dim Rid As Integer = Riddt.Rows(0).Item(0)

Assert.AreEqual(Rid, RetVal)






















'








End Sub

Tuesday, May 02, 2006

Format For OracleConnection string

Dim oradb As String = "Data Source=(DESCRIPTION=" _
+ "(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=myhost)(PORT=1521)))" _
+ "(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=PROD.World)));" _
+ "User Id=myid;Password=mypass;"



From