This is a migrated thread and some comments may be shown as answers.

Updating object created by test class's ObjectScope

6 Answers 142 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
This question is locked. New answers and comments are not allowed.
Denis Vulinovich
Top achievements
Rank 1
Denis Vulinovich asked on 27 Jul 2009, 04:07 AM
I'm trying to unit test a presenter class that updates a "Project" object. The test class has it's own ObjectScope, as per the help topic "How to: Use OpenAccess ORM with Test Frameworks". I use that ObjectScope to create the Project object, and then I pass it to the presenter. But as soon as the presenter's own ObjectScope tries to access the object, the program immediately jumps out of the current method without executing the rest of the statements.

I know this happens because I'm using two different ObjectScopes to access the same object, but I haven't found a way around it yet. I've tried using the ObjectScope from the presenter's Visual Studio project in the test class, but it behaves just the same.

6 Answers, 1 is accepted

Sort by
0
Dimitar Kapitanov
Telerik team
answered on 29 Jul 2009, 07:32 AM
Hello Denis Vulinovich,
Usually when something like this happens (in MSTest framework) it is caused by exception. Can you provide us with more details?

Sincerely yours,
Dimitar Kapitanov
the Telerik team

Instantly find answers to your questions on the new Telerik Support Portal.
Check out the tips for optimizing your support resource searches.
0
Denis Vulinovich
Top achievements
Rank 1
answered on 29 Jul 2009, 08:58 AM
Hi Dimitar,

I'm using MbUnit for my test framework. Here is the Project class.
    [Telerik.OpenAccess.Persistent()] 
    public class Project 
    { 
        private string _name; 
        private string _description; 
 
        public Project() { } 
 
        public Project( string name, string description ) 
        { 
            Name = name
            _description = description; 
        } 
 
        [FieldAlias( "_name" )] 
        public string Name 
        { 
            get { return _name; } 
            set { _name = value; } 
        } 
    } 
 

This is my TestBase class:
    [TestFixture] 
    public class TestBase 
    { 
        protected IObjectScope _scope; 
 
        [SetUp] 
        public virtual void SetUp() 
        { 
            _scope = ManagementUITestProvider.GetNewObjectScope(); 
            _scope.TransactionProperties.AutomaticBegin = true
        } 
 
        [TearDown] 
        public virtual void TearDown() 
        { 
            if ( _scope.Transaction.IsActive ) 
                _scope.Transaction.Rollback(); 
            _scope.Dispose(); 
        } 
    } 
 
You'll see that I'm using the AutomaticBegin property. I've tried setting it to false and using Transaction.Begin() instead, but it doesn't seem to make any difference.

Here is the test class. I'm using TypeMock to mock the view.
    [TestFixture] 
    [Isolated] 
    public class ProjectEditPresenterFixture : TestBase 
    { 
        IProjectView _viewFake; 
        ProjectEditPresenter _presenter; 
 
        string _projectName = "Project Name"
        Project _project; 
 
        [SetUp] 
        public override void SetUp() 
        { 
            base.SetUp(); 
            _viewFake = Isolate.Fake.Instance<IProjectView>(); 
            CreateDefaultProject();
            _presenter = new ProjectEditPresenter( _viewFake, _project ); 
        } 
 
        private void CreateDefaultProject()
        {
            _project = new Project( _projectName, _projectDesc );
            _scope.Add( _project );
            _scope.Transaction.Commit();
        }

        /// <summary> 
        /// When the OK button is clicked, check that the existing Project object is updated  
        /// in the database using the text from the Name and Description textboxes 
        /// </summary> 
        [Test] 
        public void OKButtonClicked_UpdatesProject() 
        { 
            string newName = "New Project Name"
            _viewFake.NameText = newName
 
            _presenter.OKButtonClicked(); 
 
            Project readProject = new ProjectQuery().Read( newName, _scope );   // Does a LINQ query 
            Assert.IsNotNull( readProject );    // Fails - object in database has original "Project Name"
        } 
    } 
 
The Assert fails and the database shows that the Project object is unchanged.

And here is the Presenter:
    public class ProjectEditPresenter : ProjectPresenter 
    { 
        Project _project; 
 
        public ProjectEditPresenter( IProjectView view, Project project ) : base( view ) 
        { 
            _project = project;   // _view is set in base class 
        } 
 
        public void OKButtonClicked() 
        { 
            using ( IObjectScope scope = ManagementUIProvider.GetNewObjectScope() ) 
            { 
                try 
                { 
                    scope.Transaction.Begin(); 
                    _project.Name = _view.NameText; 
                    _project.Description = _view.DescriptionText; 
                    System.Console.WriteLine( "It gets to here..." ); 
                    scope.Add( _project ); 
                    System.Console.WriteLine( "... but it doesn't get to here" ); 
                    scope.Transaction.Commit(); 
                    _view.CloseForm(); 
                } 
                catch ( Exception e ) 
                { 
                    _view.DisplayMessage( e.Message ); 
                } 
            } 
        } 
    } 
 
The ManagementUIProvider in the OKButtonClicked() method differs from the ManagementUITestProvider in the TestBase class. The two WriteLines in this method show that it executes up to the scope.Add() statement but it doesn't get to the Commit().
0
Dimitar Kapitanov
Telerik team
answered on 03 Aug 2009, 06:05 AM
Hello Denis Vulinovich,
Are you able to break in the catch block and see if/what exception is raised there?
When I looked at your code, I think you are adding the same instance to two different scopes, and I think that might cause the problem (because underneath the second scope possibly knows as well for this entity, and it might raise exception of the type "The XXX is already in the scope" or similar). Please check whether this is the case.

Sincerely yours,
Dimitar Kapitanov
the Telerik team

Instantly find answers to your questions on the new Telerik Support Portal.
Check out the tips for optimizing your support resource searches.
0
Denis Vulinovich
Top achievements
Rank 1
answered on 03 Aug 2009, 06:51 PM
Hi Dimitar,

Thanks for your reply. Here's the exception that's caught in the catch block:

Object references between two different object scopes are not allowed. The object 'Integrator.Management.Project' is already managed by 'ObjectScopeImpl 0x3f72ff5 Telerik.OpenAccess.RT.ObjectScope' and was tried to be managed again by 'ObjectScopeImpl 0x209ad8d Telerik.OpenAccess.RT.ObjectScope'

I already knew this is happening because I'm using two different ObjectScopes to access the same object, as I said in my original post. The problem is how to get around it?

I'm trying to unit test the methods in the Presenter class in isolation. So the SetUp() method of the Fixture class uses CreateDefaultProject() to store a Project object before each test, as follows:

        private void CreateDefaultProject()
        {
            ProjectFixture.DeleteAllProjects( _scope );
            _project = new Project( _projectName, _projectDesc );
            _scope.Add( _project );
            _scope.Transaction.Commit();
        }

So it's using the _scope object from the TestBase class to create the object, as per the recommendation in the help topic "How to: Use OpenAccess ORM with Test Frameworks". Then the test method calls ProjectEditPresenter.OKButtonClicked() which uses a different ObjectScope to update the object - which causes the exception.

So either I'm doing something wrong, or the help topic isn't very helpful.

0
Denis Vulinovich
Top achievements
Rank 1
answered on 05 Aug 2009, 07:26 AM
Hi Dimitar,

I've got it to work by using the ObjectScope from the Presenter in the Test class as well, using the following code in each:

    IObjectScope _scope = ManagementUIProvider.ObjectScope(); 
    _scope.TransactionProperties.AutomaticBegin = true
 

Also, I do 2 things differently to what it says in the help topic "How to: Use OpenAccess ORM with Test Frameworks":
  • I call ...Provider.ObjectScope() in each case to obtain the singleton ObjectScope instance, instead of calling GetNewObjectScope() to obtain a new instance.
  • I don't call _scope.Dispose() at the end of each test in the TestCleanup/TearDown method of the TestBase class.

The approach in the help topic doesn't work with Update and Delete operations - at least not in my case.
0
Ady
Telerik team
answered on 05 Aug 2009, 09:54 AM
Hello Denis Vulinovich,

 What you've done is perfectly fine. The setup in the article uses the scope defined in the TestBase class and all tests reuse this single scope instance. Your setup differs in the usage of the scope where the Presenter maintains its own scope instance.

 The ObjectScopeProvider( in your case the ManagementUIProvider) caches the single scope instance and it is returned when you call the 'ObjectScope' instance. If disposed after each test, you should set it to null so that you get a fresh instance the next time you call 'ObjectScope'.

Kind regards,
Ady
the Telerik team

Instantly find answers to your questions on the new Telerik Support Portal.
Check out the tips for optimizing your support resource searches.
Tags
General Discussions
Asked by
Denis Vulinovich
Top achievements
Rank 1
Answers by
Dimitar Kapitanov
Telerik team
Denis Vulinovich
Top achievements
Rank 1
Ady
Telerik team
Share this question
or