2

I have a repository implemented using LINQ to SQL. I need to do Unit Testing though I don't have a database. How can I write the UT for FreezeAllAccountsForUser method? Can you please show an example using manually mocking?

Note: There is inheritance mapping used in domain objects

Note: Unit Testing is to be done using Visual Studio Team Test

Comment from @StuperUser. Unit testing involves completely isolating code from the other objects it interacts with. This means that if the code fails, you can be sure that the failure is to do with the code under test. To do this you have to fake these objects.

CODE

     public void FreezeAllAccountsForUser(int userId)
    {
        List<DTOLayer.BankAccountDTOForStatus> bankAccountDTOList = new List<DTOLayer.BankAccountDTOForStatus>(); 

        IEnumerable<DBML_Project.BankAccount> accounts = AccountRepository.GetAllAccountsForUser(userId);
        foreach (DBML_Project.BankAccount acc in accounts)
        {
            string typeResult = Convert.ToString(acc.GetType());
            string baseValue = Convert.ToString(typeof(DBML_Project.BankAccount));

            if (String.Equals(typeResult, baseValue))
            {
                throw new Exception("Not correct derived type");
            }

            acc.Freeze();

            DTOLayer.BankAccountDTOForStatus presentAccount = new DTOLayer.BankAccountDTOForStatus();
            presentAccount.BankAccountID = acc.BankAccountID;
            presentAccount.Status = acc.Status;
            bankAccountDTOList.Add(presentAccount);

        }



        IEnumerable<System.Xml.Linq.XElement> el = bankAccountDTOList.Select(x =>
                        new System.Xml.Linq.XElement("BankAccountDTOForStatus",
                          new System.Xml.Linq.XElement("BankAccountID", x.BankAccountID),
                          new System.Xml.Linq.XElement("Status", x.Status)
                        ));

        System.Xml.Linq.XElement root = new System.Xml.Linq.XElement("root", el);


        //AccountRepository.UpdateBankAccountUsingParseXML_SP(root);
        AccountRepository.Update();

    }

Repository Layer

namespace RepositoryLayer
{
public interface ILijosBankRepository
{
    System.Data.Linq.DataContext Context { get; set; }
    List<DBML_Project.BankAccount> GetAllAccountsForUser(int userID);
    void Update();

}

public class LijosSimpleBankRepository : ILijosBankRepository
{
    public System.Data.Linq.DataContext Context
    {
        get;
        set;
    }


    public List<DBML_Project.BankAccount> GetAllAccountsForUser(int userID)
    {
        IQueryable<DBML_Project.BankAccount> queryResultEntities = Context.GetTable<DBML_Project.BankAccount>().Where(p => p.AccountOwnerID == userID);
        return queryResultEntities.ToList();
    }


    public virtual void Update()
    {
        //Context.SubmitChanges();
    }

}

}

Domain Classes

namespace DBML_Project
{

public  partial class BankAccount
{
    //Define the domain behaviors
    public virtual void Freeze()
    {
        //Do nothing
    }
}

public class FixedBankAccount : BankAccount
{

    public override void Freeze()
    {
        this.Status = "FrozenFA";
    }
}

public class SavingsBankAccount : BankAccount
{

    public override void Freeze()
    {
        this.Status = "FrozenSB";
    }
}  
}

Auto generated Class by LINQ to SQL

[global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.BankAccount")]
[InheritanceMapping(Code = "Fixed", Type = typeof(FixedBankAccount), IsDefault = true)]
[InheritanceMapping(Code = "Savings", Type = typeof(SavingsBankAccount))]
public partial class BankAccount : INotifyPropertyChanging, INotifyPropertyChanged

3 Answers 3

5

Simply, you can't. The sole purpose of the repository implementation is talking to the database. So the database technology does matter and you should perform integration tests.

Unit testing this code is impossible because LINQ to Objects is a superset of LINQ to SQL. You might have a green unit test and still get the runtime exception when using real db because you used a feature of LINQ in your repository that cannot be translated into SQL.

Sign up to request clarification or add additional context in comments.

6 Comments

But the following posts says such an approach. What do you think? stackoverflow.com/questions/7076726/… Also see stackoverflow.com/questions/4649786/…
Imagine a simple example: You created a custom property in your entity that is not mapped to table cell but computed somehow. The repository methot that uses that property in where clause will pass the unit test and fail in integration test.
What's the point of writing unit tests that give false positives?
You can create a mock of the repository that returns a list of in memory objects and validating if the Update command receives proper parameter value.
Check out Moq, Rhino Mocks, FakeItEasy. And you can always create a mock manually. Those mocking frameworks make the task just less verbose.
|
2

The Repository responsibility is to persist domain objects and fetch them on request. i.e. it's job is to take an object and deserialize/serialize it to from some form of durable storage.

So tests for the repository have to test against the real storage in this case a DB. i.e. these are integration tests - tests that your class integrates with the external DB.

Once you have this nailed, the rest of the client/app doesn't have to work against the real DB. They can mock the repository and have fast unit tests. You can assume that GetAccount works since the integration tests pass.

More details: By passing in the Repository object as a ctor or method arg, you open the doors for passing in a fake or a mock. Thus now the service tests can run without a real repository >> there is no DB-access >> fast tests.

public void FreezeAllAccountsForUser(int userId, ILijosBankRepository accountRepository)
{
  // your code as before
}

test ()
{  var mockRepository = new Mock<ILijosBankRepository>();
    var service = // create object containing FreezeAllAccounts...

    service.FreezeAllAccounts(SOME_USER_ID, mockRepository);

    mock.Verify(r => r.GetAllAccountsForUser(SOME_USER_ID);
    mock.Verify(r => r.Update());
}

4 Comments

Thanks. "They can mock the repository and have fast unit tests." Can you please explain how those Unit Tests will look like?
Can you please explain how to test FreezeAllAccountsForUser method which is not a repository method?
Thanks. Which is the mock tool used for it?
The tool itself doesn't matter.. most of them are similar. I think the syntax I've used is Moq-ish.. may not compile.
0

You can by using the IDbSet interface in your datacontext and extracting an interface for your datacontext class. Programming towards interfaces is the key to creating unit testable code.

The reason that you would want to create unit tests for these linq queries is to have a unit test for the logical query. Integration tests are subject to all kinds of false negatives. The db not being in the right state, other queries running at the same time, other integration tests, etc. It is very hard to isolate a db well enough for a reliable integration test. That is why integration tests are so often ignored. If i have to pick one, i want the unit test...

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.