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 -~----------~----~----~----~------~----~------~--~---
