chevron-thin-right chevron-thin-left brand cancel-circle search youtube-icon google-plus-icon linkedin-icon facebook-icon twitter-icon toolbox download check linkedin phone twitter-old google-plus facebook profile-male chat calendar profile-male
Welcome to Typemock Community! Here you can ask and receive answers from other community members. If you liked or disliked an answer or thread: react with an up- or downvote.
0 votes
Hi,

We have the following unit test which has started failing since we updated the solution to .Net 4.5 :

var underTest = new SingleSignOnAuthenticationModule();

         MockObject<HttpApplication> applicationMock = MockManager.MockObject<HttpApplication>();

          MockObject<HttpContext> httpContextMock = MockManager.MockObject<HttpContext>();
            applicationMock.ExpectGetAlways("Context", httpContextMock.Object);

         MockObject<HttpRequest> httpRequestMock = MockManager.MockObject<HttpRequest>();
         httpContextMock.ExpectGetAlways("Request", httpRequestMock.Object);
            
            var cookies = new HttpCookieCollection();
         cookies.Add(new HttpCookie("MySSOCookie", token));
         httpRequestMock.ExpectGetAlways("Cookies", cookies);

         MockedEvent authenticateRequestHandler = applicationMock.ExpectAddEvent("AuthenticateRequest");


         underTest.Init(applicationMock.Object);
         authenticateRequestHandler.Fire(applicationMock.Object, EventArgs.Empty);

****SNIP******


At this point, it fires into the Single Sign On module, which runs this code :

private void SignIn(SsoUserDetails user)
      {
         var ssoIdentity = new SingleSignOnIdentity(user);
         var ssoPrincipal = new SingleSignOnPrincipal(ssoIdentity);

         _context.User = ssoPrincipal;    ----- THIS LINE FAILS
         Thread.CurrentPrincipal = ssoPrincipal;
      }


All well and good to this point, except when it hits the line _context.User = ssoPrincipal.

ssoPrincipal is set to a valid object - but when it attempts to assign it to _context.User, or indeed you even interrogate _context.User - it throws a null reference exception.

My only thoughts at this stage are that User is a protected property, [SecurityPermission(SecurityAction.Demand, ControlPrincipal=true)], and in v4 changes were introduced to the security model.

Would this be why the MockManager is causing this to fail? I'd rather this test was using the Typemock model, but we don't have time to rewrite it as it's a fairly large test.

Any input very much appreciated!

Tony
asked by boltonto (1.8k points)

4 Answers

0 votes
Hi,

We tried to repro your issue with partial success.
We have the following code under test :
    public class SingleSignOnAuthenticationModule
    {
        public void Init(HttpApplication application, SingleSignOnIdentity ssoIdentity)
        { 
            var _context = application.Context;

            var ssoPrincipal = new SingleSignOnPrincipal(ssoIdentity);

            _context.User = ssoPrincipal;
        }
    }

    public class SingleSignOnPrincipal : IPrincipal
    {
        private SingleSignOnIdentity ssoIdentity;

        public SingleSignOnPrincipal(SingleSignOnIdentity ssoIdentity)
        {
            this.ssoIdentity = ssoIdentity;
        }

       public IIdentity Identity
       {
           get { throw new NotImplementedException(); }
       }

       public bool IsInRole(string role)
       {
           throw new NotImplementedException();
       }
    }


and this is the test :
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestMethod12()
        {
            var underTest = new SingleSignOnAuthenticationModule();

         MockObject<HttpApplication> applicationMock = MockManager.MockObject<HttpApplication>();

          MockObject<HttpContext> httpContextMock = MockManager.MockObject<HttpContext>();
            applicationMock.ExpectGetAlways("Context", httpContextMock.Object);

         MockObject<HttpRequest> httpRequestMock = MockManager.MockObject<HttpRequest>();
         httpContextMock.ExpectGetAlways("Request", httpRequestMock.Object);

         var cookies = new HttpCookieCollection();
         cookies.Add(new HttpCookie("MySSOCookie", "token"));
         httpRequestMock.ExpectGetAlways("Cookies", cookies);

         MockObject<SingleSignOnIdentity> ssoIdentity = MockManager.MockObject<SingleSignOnIdentity>();


         underTest.Init(applicationMock.Object, ssoIdentity.Object);
        }
    }


The problem is it fails both in .net 4 & 4.5.
Also we noticed it shows us stack trace along the nullreference exception :
[ img ]

Did you get the same stack trace ?

This stack trace was generated because the Setter of User was actually called without faking it.
We were able to pass this test with faking it with the following line :
httpContextMock.ExpectSetAlways("User");

I don't know exactly what goes wrong between 4 and 4.5
but this "User" thing seems to be the problem as I see it.

Please let me know it solved your issue.
answered by Shai Barak (1.5k points)
0 votes
Hi Shai,

Thanks for the reply!

That does the trick in terms of the nullreference - so it gets past that point now.

Weirdly though when it's come out of the init :

private void SignIn(SsoUserDetails user)
      {
         var ssoIdentity = new SingleSignOnIdentity(user);
         var ssoPrincipal = new SingleSignOnPrincipal(ssoIdentity);

         _context.User = ssoPrincipal;  <--- Here the principal is unit@tests3.com, and assigns correctly...
         Thread.CurrentPrincipal = ssoPrincipal;
      }


...and back into the test, this point fails :

Assert.AreEqual("unit@tests3.com", applicationMock.Object.Context.User.Identity.Name);


It looks like User is null, even though it was assigned the principal during the test. I also tried checking it directly using httpContextMock.Object.User, but that's also null (which is obvious I guess).

Any ideas as to why, during the test, the object has been assigned but isn't 'sticking' to the mock context?

Thanks again!
Tony
answered by boltonto (1.8k points)
0 votes
Hi Shai,

Just FYI decided to rewrite it using Isolator - figured it needed doing anyway and that's solved the problem. In the event it's of interest to anyone else, here's the code :

 [Isolated]
      [Test]
      public void AuthenticationShouldIntegrateWithDotNet()
        {

            var underTest = new SingleSignOnAuthenticationModule();

            var fakeContext = Isolate.Fake.Instance<HttpContext>();
            var fakeRequest = Isolate.Fake.Instance<HttpRequest>(Members.ReturnRecursiveFakes);
            var fakeApp = Isolate.Fake.Instance<HttpApplication>();

            Isolate.WhenCalled(() => fakeApp.AuthenticateRequest += null).CallOriginal();

            var cookies = new HttpCookieCollection();
            cookies.Add(new HttpCookie("MySsoToken", token));
            Isolate.WhenCalled(() => fakeRequest.Cookies).WillReturn(cookies);
                        
            Isolate.WhenCalled(() => fakeContext.Request).WillReturn(fakeRequest);
            Isolate.WhenCalled(() => fakeApp.Context).WillReturn(fakeContext);            
            
            underTest.Init(fakeApp);

            Isolate.Invoke.Event(() => fakeApp.AuthenticateRequest += null, fakeApp, EventArgs.Empty);

            Assert.AreEqual("unit@xxx.com", fakeContext.User.Identity.Name);

** SNIP **


Thanks again for your help, Shai.

Tony
answered by boltonto (1.8k points)
0 votes
Hi,

I was just gonna answer you to use the new API.

Glad you figured it out yourself and that it worked for you :)
answered by Shai Barak (1.5k points)
...