5

I am trying to setup unit tests for my Linq To SQL code. My code uses the System.Data.Linq.Table class (generated by the designer).

Because this class is sealed and the constructor is internal it is completely impervious to unit testing frameworks like Rhino Mocks. (Unless you want to alter you code to use the repository pattern, which I would rather not.)

Typemock can (some how) mock this class. (See here for an example.)

However, Typemock is also $800 a license. I don't see my employer springing for that anytime soon.

So here is the question. Are there any other mocking frameworks out there that don't rely on Interfaces to create the mocks?


Edit: Example of code that I need to test:

public class UserDAL : IUserDAL
{
    private IDataClassesDataContext _ctx;
    public UserDAL()
    {
        string env = ConfigurationManager.AppSettings["Environment"];
        string connectionString = ConfigurationManager
                                  .ConnectionStrings[env].ConnectionString;
        _ctx = new DataClassesDataContext(connectionString);
    }
    public UserDAL(IDataClassesDataContext context)
    {
        _ctx = context;
    }
    public List<User> GetUsersByOrganization(int organizationId)
    {
        IOrderedQueryable<User> vUsers =
            (from myUsers in _ctx.Users
             where myUsers.Organization == organizationId
             orderby myUsers.LastName
             select myUsers);
        return vUsers.ToList();
    }
    public bool IsUserInOrganization(User user, int orgainzationID)
    {
        // Do some Dal Related logic here.

        return GetUsersByOrganization(orgainzationID).Contains(user);            
    }
}

I have shorted this up to make it easier to read. The idea is that I have some code (like IsUserInOrganization that calls another method (like GetUsersByOrganization) that does a Linq query.

I would like to unit test the IsUserInOrganization method. Do do that I would need to mock _ctx.Users which is a Table class (that is sealed and has an internal constructor).

Ruben Bartelink
  • 59,778
  • 26
  • 187
  • 249
Vaccano
  • 78,325
  • 149
  • 468
  • 850
  • Two notes regarding the code: 1. Testing IsUserInOrganization should usually be separate from testing GetUsersByOrganization except in integration testing; they don't do the same thing. Tests of GetUsersByOrganization would normally include coverage of the specific usage in IsUserInOrganization. Without some additional code in the IsUserInOrganization method, there is no reason to test the method as testing GetUsersByOrganization should cover the relevant cases anyway. Basically, in this case you want to test the wrong thing, in my opinion. – Mike Burton Dec 08 '09 at 18:12
  • One calls the other. With out offloading it to a different class, how can you test one without calling the other? – Vaccano Dec 08 '09 at 18:13
  • You can't. That's a code smell, in fact. – Mike Burton Dec 08 '09 at 18:24
  • That one method calls another? How is that code smell? – Vaccano Dec 08 '09 at 19:00
  • That one method is responsible for two things and can't be decomposed. You're 1) pulling a collection of users and 2) checking for the existence of a particular user. The method as written is unnecessary, it's simply a convenience. It does nothing of value in and of itself. – Mike Burton Dec 08 '09 at 21:07
  • Well, that is true because the actual code of what is happening is too long. The actual code checks to see if an user exists and that the user name is not already in use then preforms an update on it. In both instances it calls a second method. In the real instance the second method selects a user using Linq to SQL. As they examples were similar in relation to my problem I created IsUserInOrganization to demonstrate my issue. – Vaccano Dec 08 '09 at 21:27
  • No offense, but it's a bad example. You SHOULD NOT be writing a test for IsUserInOrganization, because it is simply a wrapper for a call to another method. By definition you typically don't write tests for wrappers, they're simply a wrapper without independent functionality. Put some actual logic in there and it may become apparent how to solve your problem. – Mike Burton Dec 09 '09 at 00:23
  • That is what the comment //Do some DAL related logic here. I did not feel compelled to show the logic. But it is there and that is what I am trying to test. – Vaccano Dec 09 '09 at 16:05
  • And all this is beside the point. Even if my example is not good, the question is still a valid question. – Vaccano Dec 09 '09 at 16:05
  • The ideal mocking would return a test-initialized list from GetUsersByOrganization. You normally can't mock an internal method, so you can't provide that behaviour. This is a test smell - you're doing two things with one class, and it's making your tests hard to write. Without a more detailed code listing, it looks like the code isn't written for testability. Moreover, as written it's hard to say whether you're mixing responsibilities in IsUserInOrganization. – Mike Burton Dec 10 '09 at 20:37
  • I've been struggling to do this with Moles for more than a few hours now. Hours = $$. IMO, Moles isn't ready for primetime yet. I found a sample of mocking a table select in TypeMock that was 2 yrs old. OTOH, I can't for the life of me figure out how to get Moles to do this. Link: http://forums.typemock.com/viewtopic.php?p=2917 – jcollum Dec 20 '10 at 22:52

3 Answers3

4

Check out Microsoft Stubs that has the simple premise of:

Replace any .NET method with your own delegate!

And a more detailed description of it's capabilities (emphasis is mine).

Stubs is a lightweight framework for test stubs and detours in .NET that is entirely based on delegates, type safe, refactorable and source code generated. Stubs was designed provide a minimal overhead to the Pex white box analysis, support the Code Contracts runtime writer and encourage the programmatic models rather than record/replay tests. Stubs may be used on any .NET method, including non-virtual/static methods in sealed types.

Vaccano
  • 78,325
  • 149
  • 468
  • 850
João Angelo
  • 56,552
  • 12
  • 145
  • 147
  • Stubs has been renamed to 'Moles' – Peli Mar 21 '10 at 03:52
  • -1, from trying to use Moles to do this, I've found it to be very difficult. While in TypeMock it's this: Mock mockDC = MockManager.Mock(typeof(CustomerServicesDataContext)); mockDC.ExpectGetAlways("Categories", mockCats); --- 2 lines of code (plus building the mockCats object)! – jcollum Dec 20 '10 at 22:49
  • 1
    @jcollum, that's a pretty thin argument for downvoting an answer but you do as you please. On a side note however, I never said it was easier than TypeMock and this answers what the OP asked. If you have a TypeMock license then good for you... use it. But don't assume everyone has one. – João Angelo Dec 21 '10 at 10:14
  • @Joao: It's a valid reason to downvote an answer: I think the answer is wrong. However I've found out in the meantime that I was wrong, it is possible to do this with Moles -- there's just very little in the way of explanation of how to do it out there on the net. It's easier with TypeMock. I guess you have to edit the answer for me to take away my downvote. – jcollum Dec 21 '10 at 16:07
  • @jcollum - as you say, this can totally be done with Moles. I even posted a video of how to do it over at Dimecasts.net. (It is a bit old and uses some of out-of-date parts of Moles, but the code should be the same) I have found Moles to be very good and "ready for primetime". However, I do think that stubs (its "normal" unit testing counterpart) is not nearly a good as Rhino Mocks or NSubstitute. (NOTE: I edited the answer, unless the edit has to be done by the original answerer, you should be able to change your vote now.) – Vaccano Dec 21 '10 at 16:25
  • @Vaccano: Downvote removed. It's funny: in between me adding this comment and now, I watched that Dimecasts video. It was very helpful, exactly what I needed. I still contend that doing this sort of mocking is easier and better documented in TypeMock. – jcollum Dec 21 '10 at 16:38
  • @jcollum - I be surprised if TypeMock was not easier. Moles is new to the game, where has TypeMock has had time to get things just right. But I can't get my boss to spring for a license to it for all of the developers at my company. Since we all have MSDN Subscriptions already, Moles is "free". So we have to go with that. As long as it works (and it does) that is fine (I don't need to do this kind of unit test to often). – Vaccano Dec 21 '10 at 21:03
2

There are two standard unit testing approaches in this case:

1) Don't test the platform - if the dependency is on a framework class, you don't write tests where that interaction is verified. This typically means you substitute a dependency at test time, but in your case it likely means you inject the table itself.

2) Wrap the platform - if you need to test something that interacts with the platform, then write a wrapper layer for the relevant components

There's also integration and acceptance testing to consider. For both of these cases you would usually simply accept the dependency as it exists in your application.

What precisely are you concerned about testing that you need to directly mock/substitute this class?

Edit:

It seems as if you're looking to avoid rewriting code to be more testable. This is where TypeMock excels, and is the reason why some test advocates think TypeMock can lead to problems. It is, however, the right tool for the job if you absolutely refuse to restructure your code for testability.

Edit #2:

Perhaps I'm being overly obsessive about this, but let's consider a more testable pattern:

Organization()
{
    HasUser(name)
}

OrganizationDAL
{
    Organization LoadOrganization(id)
}

OrganizationServiceFacade
{
   IsUserInOrganization(name, orgid)
   {
       return OrgDAL.LoadOrganization(id).HasUser(name)
   }
}

Organization's natural contains test for a user no longer needs to be platform-dependent, you should be able to inject the datasource. OrganizationDAL is only responsible for loading organizations rather than returning information about organizations (although there are ways to put queries into this layer if necessary). OrganizationServiceFacade is only responsible for providing composed services, which should both satisfy mockability and avoid the need for extra unit tests (it's an Integration or possibly even an Acceptance target) since it's a wrapper class. Depending on how you construct Organizations, you can inject data without relying on a particular notion of how that data works.

Mike Burton
  • 3,010
  • 24
  • 33
-1

You may want to consider using the Repository pattern, basically it's the "wrap the platform" suggestion from Mike. With it you'll be mocking IRepository rather then the DataContext.

http://blogs.microsoft.co.il/blogs/kim/archive/2008/11/14/testable-data-access-with-the-repository-pattern.aspx

David
  • 12,451
  • 1
  • 22
  • 17