Why would I write a fake class and unit test it? - unit-testing

I understand the need to test a class that has logic (for instance, one that can calculate discounts), where you can test the actual class.
But I just started writing unit tests for a project that will act as a repository (get objects from a database). I find myself writing a 'fake' repository that implements an ISomethingRepository interface. It uses a Dictionary<Guid, Something> for storage internally. It implements the Add(Something) and GetById(Guid) methods of the interface.
Why am I writing this? Nothing I'm writing will actually be used by the software when it's deployed, right? I don't really see the value of this exercise.
I also got the advice to use a mock object that I can setup in advance to meet certain expectations. That seems even more pointless to me: of course the test will succeed, I have mocked/faked it to succeed! And I'm still not sure the actual software will perform as it should when connecting to the database...
confused...
Can someone point me in the right direction to help me understand this?
Thank you!

You are not testing your mock object but some other class that is interacting with it. So you could for example test that a controller forwards a save method call to your fake repository. There is something wrong if you are "testing your fake objects"

Don't test the mock class. Do test the production class using the mock class.
The whole point of the test support class is to have something that you can predict its behavior. If you need to test the test support class in order to predict its behavior, there is a problem.
In the fake database article you linked in a comment, the author needs to unit test his fake database because it is his product (at least in the context of the article).
Edit: updated terms to be more consistent.
Mock - created by mocking framework
Fake - created manually, might actually function some.
Test Support - Mocks, Fakes, Stubs, and all the rest. Not production.

The purpose of the mock/stub object is not to be tested instead of the unit you're trying to test, it's to allow you to test that unit without needing other classes.
It's basically so that you can test classes one at a time without having to test all the classes they're also dependent on.

You should not be testing the mock class.
What you normally do is: you create mock classes for all the classes that the class you are testing interact with.
Let's say you are testing a class called Bicycle which takes in the constructor objects of classes Wheel, Saddle, HandleBar,etc.
And then within the class Bike you you want to test test its method GetWeight which probably iterates through each part and calls property/method Weight of them and then returns the total.
What you do:
you write a mock class for each part
(Wheel, saddle etc) which simply
implements the Weight bit
then you pass those mock classes to the Bicycle
test the GetWeight method on the Bicycle class
It that way you can focus on testing the GetWeight on the Bicycle class, in a manner that is independent on other classes (say they are not implemented yet, not deterministic etc.)

Who watches the watchers?
It is interesting for example if the mock implementation throws specific Exceptions for the corner cases, so you know that the classes that use or depend the IRepositorySomething can handle the exceptions that are thrown in real life. Some of these exceptions you can't generate easily with a test database.
You do not test the Mock object with a unit test, but you use it to test classes that depend on it.

Instead of writing a fake class by yourself, you can use a tool (like Rhino or Typemock) to mock it. It is much easier than writing all the mocks yourself. And like others said, there's no need to test fake code, which is no code if you use the tool.

I have actually found two uses for the mock classes that we use in repository implementation testing.
The first is to test the services that use an implementation of the "ISomethingRepository" equivalent that you mention. However, our repository implementations are created by a factory. This means that we do write tests against the "ISomethingRepository", but not against the "MockSomethingRepository" directly. By testing against the interface, we can easily assert that the code coverage for our tests cover 100% of the interface. Code reviews provide simple verification that new interface members are tested. Even if the developers are running against the mock that the factory returns, the build server has a different configuration that tests against the concrete implementation that the factory returns within the nightly builds. It provides the best of both worlds, in terms of test coverage and local performance.
The second use is one that I am surprised that no one else has mentioned. My team is responsible for the middle tier. Our web developers are responsible for the front end of the web products. By building out mock repository implementations, there is not the artificial obstacle of waiting for the database to be modeled and implemented prior to the front-end work starting. Views can be written that will be built off of the mock to provide a minimal amount of "real" data to meet the expectations of the web developers, as well. For example, data can be provided to contain minimum and maximum length string data to verify that neither break their implementation, etc.
Since the factories we use are wired as to which "ISomethingRepository" to return, we have local testing configurations, build testing configurations, production configurations, etc. We purposely are trying to make sure that no team on the project has unreasonable wait times because of another team's implementation time. The largest chunk of wait time is still provided by the development team, but we are able to crank out our domain objects, repositories, and services at a faster pace than the front-end development.
Of course, YMMV. ;-)

You write "fake" class called Stub or Mock object because you want to test an implementation in a simple way without testing the real concrete class. The purpose is to simplify the testing by testing only the Interface (or abstract class).
In your example, you are testing something that has a dictionnary. It might be fill up in real by the database or have a lot of logic behind it. In your "fake" object, you can simplify everything by having all data constant. This way you test only the behavior of the interface and not how the concrete object is built.

There is generally no need to run classical unit tests in the Data Access Layer.
Perhaps you can write integrational style unit test for your Data Acess Classes, that is, Integration Test (= integrating your Data Access Layer Code with the DB) using the features of Unit Testing Frameworks.
For example, in a Spring project you can use Spring Testcontext to start your Spring context inside a unit test, and then connect to a real database and test that the queries returns correct results. You need probably an own database for unit tests, or perhaps you can connect them with a developer DB.

Have a look at the following article for a good explanation of this:
https://web.archive.org/web/20110316193229/http://msdn.microsoft.com/en-us/magazine/cc163358.aspx
Basically, if you write a fake object and it turns out to be fairly complex, it is sometimes worth it to unit test the fake to make sure it works as expected.
Since a repository can be complex, writing unit tests for it often makes sense.

Related

Is it acceptable to use a 'real' utility class instead of mocking in TDD?

I have a project I am trying to learn unit testing and TDD practices with. I'm finding that I'm getting to quite confusing cases where I am spending a long time setting up mocks for a utility class that's used practically everywhere.
From what I've read about unit testing, if I am testing MyClass, I should be mocking any other functionality (such as provided by UtilityClass). Is it acceptable (assuming that UtilityClass itself has a comprehensive set of tests) to just use the UtilityClass rather than setting up mocks for all the different test cases?
Edit: One of the things I am making a lot of setup for.
I am modelling a map, with different objects in different locations. One of the common methods on my utility class is GetDistanceBetween. I am testing methods that have effects on things depending on their individual properties, so for example a test that selects all objects within 5 units of a point and an age over 3 will need several tests (gets old objects in range, ignores old objects out of range, ignores young objects in range, works correctly with multiples of each case) and all of those tests need setup of the GetDistanceBetween method. Multiply that out by every method that uses GetDistanceBetween (almost every one) and the different results that the method should return in different circumstances, and it gets to be a lot of setup.
I can see as I develop this further, there may be more utility class calls, large numbers of objects and a lot of setup on those mock utility classes.
The rule is not "mock everything" but "make tests simple". Mocking should be used if
You can't create an instance with reasonable effort (read: you need a single method call but to create the instance, you need a working database, a DB connection, and five other classes).
Creation of the additional classes is expensive.
The additional classes return unstable values (like the current time or primary keys from a database)
TDD isn't really about testing. Its main benefit is to help you design clean, easy-to-use code that other people can understand and change. If its main benefit was to test then you would be able to write tests after your code, rather than before, with much of the same effect.
If you can, I recommend you stop thinking of them as "unit tests". Instead, think of your tests as examples of how you can use your code, together with descriptions of its behaviour which show why your code is valuable.
As part of that behaviour, your class may want to use some collaborating classes. You can mock these out.
If your utility classes are a core part of your class's behaviour, and your class has no value or its behaviour makes no sense without them, then don't mock them out.
Aaron Digulla's answer is pretty good; I'd rephrase each of his answers according to these principles as:
The behaviour of the collaborating class is complex and independent of the behaviour of the class you're interested in.
Creation of the collaborating class is not a valuable aspect of your class and does not need to be part of your class's responsibility.
The collaborating class provides context which changes the behaviour of your class, and therefore plays into the examples of how you can use it and what kind of behaviour you might expect.
Hope that makes sense! If you liked it, take a look at BDD which uses this kind of vocabulary far more than "test".
In theory you should try to mock all dependencies, but in reality it's never possible. E.g. you are not going to mock the basic classes from the standard library. In your case if the utility class just contains some basic helper methods I think I wouldn't bother to mock it.
If it's more complicated than that or connects to some external resources, you have to mock it. You could consider creating a dedicated mock builder class, that would create you a standard mock (with some standard stubs defined etc), so that you can avoid mocking code duplication in all test classes.
No, it is not acceptable because you are no longer testing the class in isolation which is one of the most important aspects of a unit test. You are testing it with its dependency to this utility even if the utility has its own set of tests. To simplify the creation of mock objects you could use a mock framework. Here are some popular choices:
Rhino Mocks
Moq
NSubstitute
Of course if this utility class is private and can only be used within the scope of the class under test then you don't need to mock it.
Yes, it is acceptable. What's important is to have the UtilityClass thoroughly unit tested and to be able to differentiate if a test is failing because of the Class under test or because of the UtilityClass.
Testing a class in isolation means testing it in a controlled environment, in an environment where one control how the objects behave.
Having to create too many objects in a test setup is a sign that the environment is getting too large and thus is not controlled enough. Time has come to revert to mock objects.
All the previous answers are very good and really match with my point of view about static utility classes and mocking.
You have two types of utilities classes, your own classes you write and the third party utility classes.
As the purpose of an utility class is to provide small set of helper methods, your utility classes or a third party utility classes should be very well tested.
First Case: the first condition to use your own utility class (even if static) without mocking, is to provide a set of valid unit tests for this class.
Second Case: if you use a third party utility library, you should have enough confidence to this library. Most of the time, those libraries are well tested and well maintained. You can use it without mocking its methods.

Rhino Mocking and TDD with legacy code

First of all let me say I am working from legacy code. So some changes can be made but not drastic ones.
My problem is I have a "Vehicle" object, it is pretty simple but has no interfaces or anything on it. This project was created before TDD really started to become more main stream. Anyway, I need to add a new method to change the starting mileage of the vehicle. I thought this would be a good start to try TDD and Mocking as I am new it all. My problem is I need to create a vehicle do some checks which involve going to the database. Sorry if my question is not 100% clear, is why I am posting as I am a bit confused where Rhino Mocks fits in (and if I need it!).
The problem is dependencies. Your vehicle class depends on the database. Hopefully all the interactions with the database have been encapsulated into a nice class we will get back to that in a second. When you fire off your unit test you want to be able to test the vehicle class without having to care about the database. For example you want to check that your SpeedUp(int x) method really increases the total speed by x. In this method the first thing it does is it asks the DB for its current speed. That means that you have to have a DB to test! Dam, that doesn't sound like a very fast test nor repeatable. Also a lot of setup to just run a test.
Wouldn't it be great if we could have a pretend DB? That is where mocking comes in. We create a Mock of the class that has all the DB interaction encapsulated. We then setup the mock to respond with a prepgrammed value. So for example when we ask the DB for current speed you return 100.
So now when we test the mock returns a 100 and we can assert that SpeedUp(int x) takes 100 and adds x to it.
Rhino mocks can only create mocks from interfaces or abstract classes, which do not exist your legacy code.
TypeMock can mock anything but isn't free.
You could use Microsoft Moles to mock these out.
You should however take into account that Moles should be your last resort solution, it's better to refactor your code and make it testable by abstracting your datalayer from your business layer.
HTH
Is it easy to create an instance of the Vehicle type (an object) and then invoke your method for a test ? If yes, then chances are you don't need a mock.
However if your Vehicle type has dependencies (like a Database access object) that it needs to perform the action that you want to test, then you would like to use a mock database access object that returns canned values for the test since you want your unit tests to run fast.
Vehicle [depends On>] OwnerRepository [satisfied By] SQLOwnerRepository
So you introduce an interface (an OwnerRepository to get details of the owner, let's say) to separate the DB Interaction (define a contract) between the two. Make your real dependency (here SQLOwnerRepository) implement this interface. Also design your code such that dependencies can be injected e.g.
public Vehicle (OwnerRepository ownerRepository)
{ _ownerRepository = ownerRepository; // cache in member variable }
Now in the test code,
Vehicle [depends On >] OwnerRepository [satisifed By] MockOwnerRepository
You have frameworks that given an interface would create a mock implementation of it (See Rhino/Moq frameworks). So you no longer need an actual DB connection to test your Vehicle class. Mocks are used to abstract away time consuming / uncontrollable dependencies in order to keep your unit tests fast / predictable.
I'd recommend reading up on "Dependency Injection" to have a better understanding of when and why to use mocks.
Not a direct answer to your question. However it is worth to take a look at the following.
Gabriel Schenker has posted about applying TDD in legacy systems. PTOM – Brownfield development – Making your dependencies explicit
This article explains about making dependencies explicit and using Dependency Injection. It also tell s about Poor Man’s Dependency Injection. This is needed when there is only default constructor.
Something like
public OrderService() : this(
new OrderRepository(),
new EmailSender(ConfigurationManager.AppSettings["SMTPServer"])
)
The article also deals with creating a wrapper for ConfigurationManager for making it testable.

Mock Objects vs Test Database

What's the advantage of using mock objects in comparison to a static test database that has known data and using transactions to make sure nothing changes when testing against the database.
You can do both. Use mock objects to test you BLL logic and then use a test database to test your DAL logic. That way if something breaks you can easily see where the problem lies by which test fails.
Firstly, using a mock will be much quicker than connecting to an external database. However the main reason is that mocks behave the same each time the test is run, which you can't guarentee with an external service like a database, which means unit tests don't fail randomly. You can also easily simulate any types of failure you want to handle with a mock object.
It's also a good idea to run integration tests against a real database however to test things like configuration and performance.
If you can ensure that the static test db doesn't change during testing then I think static test db is better than mock objects. But, then it depends on what you want to test and the complexity of the code being tested. I would go with mock objects as they are simpler to maintain compared with a db.
Imagine you're about to write a class which doesn't exist. Maybe it's a controller. It's not something which talks straight to the database.
You have a good idea of how it ought to behave, and you know what it should be responsible for, and what it should delegate to some other service (using Single Responsibility Principle). So you write interfaces to represent the roles of the helper classes it's going to use.
Then you write an example of how you might use your class that you're about to create. If you like, you can call the example a unit test. You mock out the interactions with the helper classes. When you run the example, it fails, because you haven't written the code yet. You can now write the code to make it pass, using the interfaces of the helper classes - which you also haven't written yet.
Then you do the same with the helper classes, mocking out their helpers.
Eventually you'll reach a class which talks to the database. Or maybe it talks to a web service. Or perhaps the data is static, or in memory. (It doesn't matter to the original class, because your class is decoupled from this).
At this point you'll want an example to describe the behaviour of this class, too, and if it's a database connector, you'll need a database for the example.
Writing code this way produces code that's easy to use and understand, with nothing extra that isn't needed by something further up the stack. This is usually more robust than code that's easier to write. That's why we sometimes use mocks - because writing tests first using mocks helps produce good, maintainable, decoupled design.
Usually you would use both of these approaches.
For unit tests you would use mocked objects. This way you can test your system in a much more fine-grained way, because you can mock every object - not only the ones that wrap the database connection. In general it is good practise to unit test every class in separation of all the dependencies. The benefits are - its is possible to test all the error handling on all levels and make sure you test all the code paths, when you get a test failure you can immediately find the cause, etc.
For integration and end-to-end tests you test big parts of the system or the whole thing. Then you would connect to the database (because this connection is part of the test). Obviously you have to ensure that the database is in a known state, etc., etc.
You will end up having much more unit tests than integration tests, so its actually quite important to make them very quick - yet another advantage of using mock objects.
The setup for testing with a db can be arduous. If you find yourself spending more time in setting up the db, just to test some functional aspect of your business logic, then you might want to use a mock/fake.

Why Create Mock Objects?

During a recent interview I was asked why one would want to create mock objects. My answer went something like, "Take a database--if you're writing test code, you may not want that test hooked up live to the production database where actual operations will be performed."
Judging by response, my answer clearly was not what the interviewer was looking for. What's a better answer?
I'd summarize like this:
Isolation - You can test only a method, independently on what it calls. Your test becomes a real unit test (most important IMHO)
Decrease test development time - it is usually faster to use a mock then to create a whole class just for help you test
It lets you test even when you don't have implemented all dependencies - You don't even need to create, for instance, your repository class, and you'll be able to test a class that would use this repository
Keeps you away from external resources - helps in the sense you don't need to access databases, or to call web services, or to read files, or to send emails, or to charge a credit card, and so on...
In an interview, I'd recommend including that mocking is even better when developers use dependency injection, once it allows you to have more control, and build tests more easily.
When unit testing, each test is designed to test a single object. However most objects in a system will have other objects that they interact with. Mock Objects are dummy implementations of these other objects, used to isolate the object under test.
The benefit of this is that any unit tests that fail generally isolate the problem to the object under test. In some cases the problem will be with the mock object, but those problems should be simpler to identify and fix.
It might be an idea to write some simple unit tests for the mock objects as well.
They are commonly used to create a mock data access layer so that unit tests can be run in isolation from the data store.
Other uses might be to mock the user interface when testing the controller object in the MVC pattern. This allows better automated testing of UI components that can somewhat simulate user interaction.
An example:
public interface IPersonDAO
{
Person FindById(int id);
int Count();
}
public class MockPersonDAO : IPersonDAO
{
// public so the set of people can be loaded by the unit test
public Dictionary<int, Person> _DataStore;
public MockPersonDAO()
{
_DataStore = new Dictionary<int, Person>();
}
public Person FindById(int id)
{
return _DataStore[id];
}
public int Count()
{
return _DataStore.Count;
}
}
Just to add on to the fine answers here, mock objects are used in top-down or bottom-up structural programming (OOP too). They are there to provide data to upper-level modules (GUI, logic processing) or to act as out mock output.
Consider top-down approach: you develop a GUI first, but a GUI ought to have data. So you create a mock database which just return a std::vector<> of data. You have defined the 'contract' of the relationship. Who cares what goes on inside the database object - as long as my GUI list get a std::vector<> I'm happy. This can go to provide mock user login information, whatever you need to get the GUI working.
Consider a bottom-up approach. You wrote a parser which reads in delimited text files. How do you know if it is working? You write a mock 'data-sink' for those object and route the data there to verify (though usually) that the data are read correctly. The module on the next level up may require 2 data sources, but you have only wrote one.
And while defining the mock objects, you have also define the contract of how the relationship. This is often used in test-driven programming. You write the test cases, use the mock objects to get it working, and often than not, the mock object's interface becomes the final interface (which is why at some point you may want to separate out the mock object's interface into pure abstract class).
Hope this helps
Mock objects/functions can also be useful when working in a team. If you're working on a part of the code base that depends on a different part of the code base that some else is responsible for - which is still being written or hasn't been written yet - a mock object/function is useful in giving you an expected output so that you can carry on with you're work without being held up waiting for the other person to finish their part.
Here are the a few situations where mocking is indispensable:
When you are testing GUI interaction
When you are testing Web App
When you are testing the code that interacts with hardware
When you are testing legacy apps
I will go a different direction here. Stubbing/Faking does all of the things mentioned above, but perhaps the interviewers were thinking of mocks as a fake object that causes the test to pass or fail. I am basing this on the xUnit terminology. This could have lead to some discussion about state testing verses behavior / interaction testing.
The answer they may have been looking for is: That a mock object is different than a stub. A stub emulates a dependency for the method under test. A stub shouldn't cause a test to fail. A mock does this and also checks how and when it is called. Mocks cause a test to pass or fail based on underlying behavior. This has the benefit of being less reliant on data during a test, but tying it more closely to the implementation of the method.
Of course this is speculation, it is more likely they just wanted you to describe the benefits of stubbing and DI.
To take a slightly different approach (as I think mocks have been nicely covered above):
"Take a database--if you're writing test code, you may not want that test hooked up live to the production database where actual operations will be performed."
IMO a bad way of stating the example use. You would never "hook it up to the prod database" during testing with or without mocks. Every developer should have a developer-local database to test against. And then you would move on test environments database then maybe UAT and finally prod. You are not mocking to avoid using the live database, you are mocking in order that classes that are not directly dependent on a database do not require you to set up a database.
Finally (and I accept I might get some comments on this) IMO the developer local database is a valid thing to hit during unit tests. You should only be hitting it while testing code that directly interacts with the database and using mocks when you are testing code that indirectly access the database.

How to avoid duplicating test code

I have written my units tests, and where external resources are needed it is dealt with by using fakes.
All is good so far. Now i' am faced with the other test phases, mainly integration where i want to repeat the unit test methods against real external resources e.g The Database.
So, What are the recommendations for structuring test projects for Unit Vs Integration testing? I understand some people prefer separate assemblies for unit and Integration?
How would one share common test code between the two assemblies? Should i create a thrid assembly which contains all the Abstract Test Classes and let the unit and integration inherit? I am looking for maximum re-usability...
I hear alot of noise about Dependency Injection (StructureMap), How could one utilise such a tool in the given Unit + Integration test setup?
can anyone share some wisdom? Thanks
I don't think you should physically separate the two. A good solution is to put the Microsoft.TeamFoundation.PowerTools.Tasks.CategoryAttribute above your tests to identify regular and integration tests. When running tests (even with MSBuild) you can decide to run only the tests you're interested in.
Alternatively you can put them in seperate namespaces.
For code that will be executed in setup & teardown phases, the base class approach would work well. For integration tests, you can extract the functionality of your unit tests into well-parameterized non-test methods (preferably placed in another namespace) and call these "common" methods from both unit and integration tests. Putting unit tests, integration tests and common methods into separate namespaces would suffice, there would be no need for extra assemblies.
One approach would be to create a separate file with helper methods that would be used across multiple testing contexts, and then include that file in both your unit tests and your functional tests. For the parts that vary, you could use dependency injection - for example, by passing in different factories. In the unit tests, the factory could build a fake object, and in the functional tests it could insert a real object in to your test database.
Whether you split the tests into two projects or keep them in one might depend on the number of classes/tests you have. Too many classes in a single project would make it difficult to dig through. If you do split them out, helper/common methods could be thrown into a third assembly, or you could make them public in the unit test assembly, and let the integration assembly reference that one. Make things only as complex as you have to.
On our project we have both integration and unit tests together but in separate folders. Our project layout is such that we have separate assemblies for the main sections (Domain, Services, etc). Each assembly has a matching test assembly. Test assemblies are allowed to reference other test assemblies.
This means Services.Test can reference Domain.Test which makes sense to us because Services references Domain in the actual code.
In terms of reusable pieces we have
Builders - These provide a fluent interface for creating the most important/complex objects in our domain. These live in the main test folder for our domain. Our domain test assembly is referenced by all other test assemblies.
Mothers - These insert data into the database. They give back an Id for the inserted row which can be used to load the object if required. These live in the main test folder for our services.
Helpers - These are guys that do small things throughout our testing. For instance we prefer to allow access to collections via IEnuermable so we have a CollectionHelper.AssertCountIsEqualTo<_T>(int count, IEnumerable<_T> collection, string message) which wraps the IEnumerable in a List and asserts a count. Our Helpers all live in a common test which every other test references.
As for an IoC container if you can use one on your project they can be a huge help not only in testing (via auto mocking) but also in general development. With the overheard of registering everything with the contain though it might be a bit much for just testing.
After some experimenting this is how you can re-use test methods:
public abstract class TestBase
{
[TestMethod]
public void BaseTestMethod()
{
Assert.IsTrue(true);
}
}
[TestClass]
public class UnitTest : TestBase
{
}
[TestClass]
public class IntegrationTest : TestBase
{
}
The unit and integration test class will pick up the base class test methods and run them as two separate tests.
You should be able to create a parametised constructor on the base class to inject your mocks or resources.
I think this method can olny be used with classed within the same assembly. So it looks like the single assembly approach will have to do for now.
Thanks for the tips ppl!
If the only difference between many of your unit tests and the corresponding integration tests is that the latter use "real" ressources rather than fakes (mocks), one approach is the following:
Make a flag is_unit_test available to your test class from the outside
In the class setup, make fake or real resources available depending on the flag. For instance if you need to use a DB API that is either real (an instance of class DBreal) or fake (an instance of class DBfake), your initialization may look like if is_unit_test then this.dbapi = new DBfake else this.dbapi = new DBreal. (DBreal and DBfake need to conform to the same interface, let's call it DBapi.)
From the point of view of your test methods, step 2 amounts to (manual) Dependency Injection: The method does not know what class actually implements its dependency (the DB API). Rather, the dependency is injected into the method from the outside.
Where your test cases require the DB API, they use this.dbapi
Now you execute one and the same test class with the flag set for unit testing and without the flag set for integration testing. (How to make the flag available depends on your unit testing framework.)
Obviously, the same approach can be used if you need more than one resource in a test class.
Some people will find the explicit if in step 2 ugly. To make it more "elegant", you could employ an Inversion of Control (IoC) container (in Java for instance Spring or PicoContainer) to semi-automate the Dependency Injection instead. The initialization would then look like this.dbapi = myContainer.create(DBapi).
In simple cases, an IoC container will only complicate things, because configuring the container is not trivial, involves learning, opens the possibility of a new class of mistakes, and involves additional files.
In more complex cases however, the container makes things easier, because if the creation of your resources requires still other resources, the container will take care of their initialization as well and complexity would indeed go down. But unless you really get there, I suggest to KISS.
Unless you have an important reason for separate assemblies, they violate KISS. I suggest to wait for that reason first.
(Note that some people may tell you that Dependency Injection is only done at the class level.
I consider this unwarranted dogmatism. Injection simply means that a caller does not know the exact class it is calling, no matter how it obtained the object. It often becomes more useful when applied at the class level, but depending on your test framework this may make things overly complicated in the above case. Note that some test frameworks have their own injection capabilities, though.)