Mocking Membership provider

So as usual with so many of .NET 1.0 to .NET 2.0 era classes, Microsoft have made it near impossible to mock out MembershipProvider. The MembershipProvidersCollection class is read-only so you can’t just add your own provider at runtime.

No matter! After some time with Reflector and some twiddling with reflection I came up with a way to add a mocked out MembershipProvider.

        public static void AddMembershipProvider(this ProviderCollection providers, string providerName, MembershipProvider provider)
        {
            GetMembershipHashtable().Add(providerName, provider);
        }
 
        public static void RemoveMembershipProvider(this ProviderCollection providers, string providerName)
        {
            GetMembershipHashtable().Remove(providerName);
        }
 
        static Hashtable GetMembershipHashtable()
        {
            var hashtableField = typeof(ProviderCollection).GetField("_Hashtable", BindingFlags.Instance | BindingFlags.NonPublic);
            return hashtableField.GetValue(Membership.Providers) as Hashtable;
        }

I then called the above methods from my SetUp and TearDown methods so as to ensure the next test doesn’t run with the same providers. I’m using Moq to generate the mocks in the example code below:

        private Mock<MembershipProvider> _membership;
        private MockFactory _factory;
 
        [SetUp]
        public override void Setup()
        {
            _factory = new MockFactory(MockBehavior.Strict);
            _membership = _factory.Create<MembershipProvider>();
            Membership.Providers.AddMembershipProvider("MyMembershipProvider", _membership.Object);
        }
 
        [TearDown]
        public override void Teardown()
        {
            Membership.Providers.RemoveMembershipProvider("MyMembershipProvider");
        }

I know you’re not supposed to access private variables blah blah because they can change blah blah break your code blah blah blah but I don’t care. The code is all in one place and my unit tests are part of my continuous build. If Microsoft happen to decide to change the implementation, I should get a notification from TeamCity as soon as I upgrade. In the meantime, I’ll be happily unit testing my code.

Okay, this took me far too long to figure this out. Mainly due to my own misunderstanding of Python terminology regarding modules (For the record, a ‘module’ is a file not a directory of python files) and mainly because I couldn’t find a specific example for what I wanted to achieve. My goal was this: Given a directory full of unit tests, run all the unit tests that can be found. I wanted to be able to drop in new unit tests without having to include them somewhere.

This is what I managed to come up with:

#!/usr/bin/python
 
import unittest2 as unittest
 
if __name__ == "__main__":
    all_tests = unittest.TestLoader().discover('tests', pattern='*.py')
    unittest.TextTestRunner().run(all_tests)

It uses the (apparently) new discover method. I’m still using Python 2.6 which doesn’t have access to this method so I had to install unittest2 which is a backport from Python 2.7. If you do happen to be running Python 2.7, you can simply run this (found in the unittest documentation):

python -m unittest discover project_directory ‘*.py’

4 hours later and it’s 2 lines of code (WHICH I KNEW IT WOULD BE! AAARGH!). No matter. I won’t forget my module lesson in a hurry.

I was sitting with the problem that every time I connected to my company’s VPN my internet stopped working. After trawling through through a bug on Launchpad, I came across a solution. Basically, do the following:

  1. With the Network Manager, under VPN connections, select ‘Configure VPN Connections’
  2. Choose your VPN and select Edit
  3. Go to the IPv4 tab, and select Routes
  4. Select the check box, ‘Use this connection only for resources on its network’

What’s going on here is the concept of split tunneling. This is where you can access the Internet and your company network at the same time. What I wasn’t aware of is that this is actually a vulnerability. I have my own firewall at home so I feel that this protects the internal network from the big bad Internet.

What’s confusing is that on Windows, this is the default behavior of the cisco client (not surprising as it is less secure, but more usable). It seems like a sensible default for Linux but it’s a little frustrating trying to find the solution. From a usability perspective, I would suggest that the option be more prominent for the user. When you select it, a dialog could be displayed that briefly describes the risk to the user.

Windows Telnet Echo On

I recently pulled my hair out looking for how to enable echo during a windows telnet session. Turns out it’s pretty straightforward (as it usually is…)

  1. Get to a command prompt and type telnet
  2. At the telnet prompt type set localecho

And that’s it.

In the second part of this tutorial, we got to the point of being able to load entities from the database and display them on a page.

For this tutorial, we will handle the creation of a new Entry object with a form, handle the submission of the form and redirect after post back to the list of entries that we created in part 2 of this tutorial.

The goal

The user must be able to navigate to a form where they can enter a title and some text for a new blog entry. The user must be able to save this entry by submitting a form and should then be redirected to a list of all existing blog entries. If the user hits refresh on the list of blog entries, the most recent entry should not be duplicated.

Changes to configuration files

Firstly, we’re going to need to map a url for this new action. To accomplish this we need to change the ParameterizedUrlHandlerMapping section of the spring-servlet.xml file.

spring-servlet.xml (ParameterizedUrlHandlerMapping bean and new controller)

<bean class="carbonfive.spring.web.pathparameter.ParameterizedUrlHandlerMapping">
      <property name="alwaysUseFullPath" value="false" />
      <property name="interceptors">
         <list>
            <ref bean="hibernateInterceptorSessionInView" />
         </list>
      </property>
      <property name="defaultHandler" ref="homeController"/>
      <property name="mappings">
         <props>
            <prop key="/index">homeController</prop>
            <prop key="/entry/create">createEntryController</prop>
         </props>
      </property>
   </bean>
 
   <bean id="createEntryController" class="com.tutorial.webapp.EntryCreateController">
      <property name="formView" value="entryform" />      
   </bean>

Controller for the create page and changes to repository

EntryRepository

To be able to save our entry, we need to add a save method to our EntryRepository.

@Transactional(readOnly = false)
public void store(Entry entry) {
   Session session = sessionFactory.getCurrentSession();
   session.save(entry);
   session.flush();
}

EntryCreateController

For our form controller, we can extend an existing Spring Controller class called the SimpleFormController. This class makes it simple to specify a form view, a success view and your command object.

Lets discuss what you will see in the controller class.

  • @Controller – this identifies the class as a Spring controller.
  • @Autowired – this allows Spring to populate our entryRepository.
  • @RequestMapping – in this usage, we are mapping http method requests onto a specific method.
  • @ModelAttribute – in this case is our command (form) object that we ask Spring to bind for us
@Controller
public class EntryControllerCreate extends SimpleFormController {
 
   @Autowired private EntryRepository entryRepository;
 
   @RequestMapping(method = RequestMethod.GET)
   public String showForm(   HttpServletRequest request,
                     HttpServletResponse response,
                     ModelMap model) {
 
      model.put("entry", new Entry());
      return getFormView();
   }
 
   @RequestMapping(method = RequestMethod.POST)
   public String processSubmit(   @ModelAttribute("entry")Entry entry,
                           HttpServletRequest request,
                           HttpServletResponse response,
                           SessionStatus status,
                           ModelMap model){
      entryRepository.store(entry);
      return "redirect:"+getSuccessView();
   }
}

Template

Then we need an html file to put the form on.

entryform.html

[#import "/spring.ftl" as spring /]      
<html>
<head>
  <title>Create Entry</title>
</head>
<body>
 
   <form method="post" id="entry" name="entryForm">
      <p>
         <button class="button" type="submit" name="submit" id="update">Update</button>
         <br/>Entry Title:   [@spring.formInput "entry.title"/]
         <br/>Entry Text:   [@spring.formInput "entry.text"/]
      </p>
      <br/>
   </form>
</body>
</html>

Running the application

You should now be able to run the application and create a blog entry with a title and some text.

How do we handle errors?

In this example we aren’t going to handle any errors – we’ll cover that in another tutorial at a later stage.

Why is redirect after post good practise?

While this is best practise it is not a hard and fast rule. The main reason behind it is that if you don’t redirect, the user can refresh the page and the form will be resubmitted. In some cases this can be the desired behaviour (checking availability of tickets) and in some cases it is really undesired (resubmitting payment information).

In each case it’s up to you to decide what will be best for your users.

Coming up in Part 4

We will update our code to be able to handle editing entries.

« Previous Entries  Next Page »