Pergunta

Is anyone else frustrated with the built in ASP.NET unit testing framework? The problem I am having is connecting and testing against the Membership provider for ASP.NET in a MVC3 application. It looks like the database connection has not been established or that there is a different set of rules in place then when I run the application normally. Here are the two scenarios.

1) Attempting to find an existing user by name:

Unit Test -

    [TestMethod]
    public void RegisterTest()
    {
        AccountController target = new AccountController(); 
        RegisterModel model = new RegisterModel() { UserName = "existinguser", Email = "email@test.com", Password = "Password", ConfirmPassword = "Password" };
        actual = target.Register(model);
    }

Code chunk from the AccountController -

            MembershipCreateStatus createStatus;
            MembershipUserCollection members = Membership.FindUsersByName(model.UserName);
            MembershipUser user = null;
            if (members.Count > 0)
                createStatus = MembershipCreateStatus.DuplicateUserName;

Result - When I step into this code the members array is empty even though I know this user to be in the system. Is there some trick to establishing a connection to the membership store in the unit testing application? I have attempted using the datasource attribute with no success.

2) Attempting to create a new membership account: The unit test is the same as above however I am passing a new user that is not already in the system. When I step into the controller and get to the following line it gives me a membershipCreateStatus of 'InvalidQuestion'. This seems odd since when running this live I don't have that problem and can create accounts with the line as it is.

user = Membership.CreateUser(model.UserName, model.Password, model.Email, string.Empty, string.Empty, true, null, out createStatus);

Thanks in advance for your help. I am really trying to do this test first method but it's making it harder using the built in testing framework. Certainly there is a way to connect to the DB for all the unit tests (not providing a connection for each test) and simulate the same actions I would through a browser.

Foi útil?

Solução

When you run your unit tests it will effectively run as a new application and will therefore use its own config file - in other words not web.config that your MVC app uses. So what I would guess you are missing without more information is an entry in the app.config file in your test project, for the connection string to the database that holds your membership information (you may also be missing app.config).

If you are trying to take a TDD approach you should be writing unit tests and if you need to connect to a database for the unit tests to run, they are probably integration tests rather than unit tests. Because the Membership classes use static methods this makes things difficult. What I would recommend is wrapping the membership functionality up in it's own service with a corresponding interface (IMembershipService for example) which can then be injected by your IoC container. For the purposes of your unit tests, you can then simply mock the IMembershipService interface that you created with no need to connect to your database.

Outras dicas

I had the same problem. And yes it looks like my unit tests are more like integration tests but I just needed to test the controllers and speed wasn't a concern at this point in the project. I basically added all the sql memberbership config and connection string from the MVC 3 project's web.config to test project's app.config and the membership provider worked when the unit tests ran. Below is my test project's app.config in it's entiriety.

<?xml version="1.0" encoding="utf-8"?>
<!-- 
    Note: Add entries to the App.config file for configuration settings
    that apply only to the Test project.
-->
<configuration>
  <appSettings></appSettings>
  <connectionStrings>
    <add name="ApplicationServices" connectionString="mySqlServer;initial catalog=mySqlMembershipDB;persist security info=True;user id=mySqlUser;password=mySqlPassword;" providerName="System.Data.SqlClient" />
  </connectionStrings>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.0.5.0" newVersion="4.0.5.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>

  <system.web>
    <membership defaultProvider="AspNetSqlMembershipProvider">
      <providers>
        <clear />
        <add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="ApplicationServices" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="true" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" />
      </providers>
    </membership>
    <profile defaultProvider="AspNetSqlProfileProvider">
      <providers>
        <clear />
        <add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="ApplicationServices" applicationName="/" />
      </providers>
    </profile>
    <roleManager enabled="false" defaultProvider="AspNetSqlRoleProvider">
      <providers>
        <clear />
        <add name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="ApplicationServices" applicationName="/" />
      </providers>
    </roleManager>
  </system.web>
</configuration>
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top