I think what's happening is that there are two different transaction
contexts in play -- one for each thread.

The main thread of the test runs in one transaction context provided by the
[Rollback] attribute and the background thread is probably getting its own
transaction context.  Because the first transaction has not been committed
yet (thanks to [Rollback] the second transaction cannot see the changes that
were made.

Just a guess.

If this is indeed the case, then you'd need to ensure that the operations
performed by the ScheduleTimer thread get enlisted in the transaction
context of the main test thread somehow.  I'm afraid I don't know how to
help you with that off-hand since I've not worked with the MS ORM stuff
myself.

Happy holidays,
Jeff.

-----Original Message-----
From: [email protected] [mailto:[EMAIL PROTECTED] On
Behalf Of CVertex
Sent: Saturday, December 29, 2007 11:35 PM
To: MbUnit.User
Subject: MbUnit Rollback Threaded Issues


Hi Guys,

I'm a new TDD'er and I'm already witnessing significant increases in bug
findings in my own code. I can't understand how I built software in the past
without MbUnit and Rhino Mocks. I support webforms was a big set back, but
now that MS MVC is in the works, i'm building more reliable sites already.

The idea of creating mock harnesses, environments and relationships is kinda
addictive for exploring the limits of function. But, when I can't think of a
good way to test my DAL. Now 3.5 is out, I've jumped onto LINQ-to-SQL ORM
cos it's so well implemented, but unit testing it isn't very easy. For those
that have jumped onto MS ORM, is there a general pattern I can follow to
unit test my DAL?

Since I can't mock or fake my DAL, I'm writing to the database in each test
and relying on RollbackAttribute to erase the changes. This works great for
simple single threaded tests, but I'm having issues accessing database
changes in a thread separate to the [Test] method.

I'm trying to test a simple scheduling system. The code for the class
is:

public class ReminderManager {
        public const string ReminderManagerKey = "ReminderManager";

        private ScheduleTimer timer = new ScheduleTimer();
        public ScheduleTimer Timer { get { return timer; } }

        private DateTime lastCheckTime = DateTime.Now;
        public DateTime LastCheckTime { get { return lastCheckTime; } }

        public event Schedule.ExceptionEventHandler CheckError
        {
            add
            {
                timer.Error += value;
            }

            remove
            {
                timer.Error -= value;
            }
        }

        public void SetUpTimer(IScheduledItem schedule) {
            timer.AddJob(schedule, new Action(CheckForReminders));
            timer.Start();
        }
        public void TearDownTimer() {
            timer.Stop();
        }

        protected virtual void CheckForReminders() {

            DateTime now = DateTime.Now;


            // check for reminders between now and last event
            CharlesNicholasDataContext db = new
CharlesNicholasDataContext();
            var reminders = from r in db.Reminders where
r.DateTime>lastCheckTime && r.DateTime<=now
                            select r;

            int numrems = db.Reminders.Count();
            foreach (var reminder in reminders) {
                Launch(reminder);
            }

            // update last checked
            lastCheckTime = now;
        }

        protected virtual void Launch(Reminder reminder)
        {
            string message = "{3} Should send SMS to {0} on number {1}";
            Console.WriteLine(message, reminder.Client.FirstName,
reminder.Client.MobileNumber,reminder.DateTime.ToShortTimeString());
        }

    }

My First test checks that CheckReminders is called periodically. I use the
Test specific subclass pattern to override CheckReminder for the following
test:
        [Test]
        [Duration(4000d)]
        public void EnsurePeriodicReminderChecking()
        {
            var rmtest = new ReminderManagerTest();
            rmtest.SetUpTimer(HalfSecondSchedule());
            System.Threading.Thread.Sleep(750);
            Assert.IsTrue(rmtest.NumberOfChecks == 2); // 2 includes start
of timing AND first tick
            rmtest.TearDownTimer();
        }

The second test is causing me grief - it needs to test that reminders of the
specific criteria are actually discovered and launched.
        [Test]
        [RollBack]
        [Duration(4000d)]
        public void LaunchSms() {
            // add fake but valid db data
            var client = FakeClient();
            db.Clients.InsertOnSubmit(client);
            db.SubmitChanges();

            var message = FakeMessage();
            db.ReminderMessages.InsertOnSubmit(message);
            db.SubmitChanges();

            var rem = FakeReminder();
            rem.ReminderMessageId = message.Id;
            rem.ClientId = client.Id;
            db.Reminders.InsertOnSubmit(rem);
            db.SubmitChanges();

            // run once off timer
            manager.SetUpTimer(OnceOff());
            int numres = db.Reminders.Count();
            System.Threading.Thread.Sleep(20000);

            // TODO check sms message is launched
            // TODO check send sms return code is given

        }

So, in the test thread, I create a fake reminder, message and client and
submit to the database. Then in the ReminderManager
CheckReminders() it needs to read those fake records and should find the
fake records.

In the [Test] method, the numRes integer is 2, but in the
CheckReminders() method, numRes is 1. It's like the db changes in the first
thread aren't visible from the second, even though no exception is thrown.

Is there an obvious explanation for that? Will the removal of Rollback make
the database changes visible from the ReminderManager ScheduleTimer thread?

This is a bit mind boggling.

Thanks for your help,
-Vijay


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"MbUnit.User" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/MbUnitUser?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to