Coder Social home page Coder Social logo

let.cs's Introduction

Let.cs

build nuget

When testing in C# it's not unusual to test instances of a class. The problem we all face is having a place to initialize our objects.

  1. Create a field that is initialized and reset on [TearDown]?
  2. Create a null field that is initialized during [SetUp]?
  3. Duplicate the initialization in every [Test]?

All three of these are valid, and unfortunately, all three can be found in the same project and sometimes the same test!

namespace DoYourTestsLookLikeThis
{
    [TestFixture]
    public class InsertTearsEmoji
    {
        private UnitOfWork _work = new UnitOfWork();
        private Mock<IArticlesService> MockArticlesService { get; set; }

        [SetUp]
        public void BeforeEach()
        {
            MockArticlesService = new Mock<IArticlesService>(_work);
        }

        [TearDown]
        public void AfterEach()
        {
            // ๐Ÿ˜ญ๐Ÿ˜ญ๐Ÿ˜ญ
            _work = new UnitOfWork();
        }

        [Test]
        public void IndexShouldLoadPublishedArticles()
        {
            var controller = new ArticlesController(MockArticlesService.Object);

            controller.Index();
            MockArticlesService.Verify(service => service.Published(), Times.Once);
        }
    }
}

It's dangerous to go alone, take Let.cs with you ๐Ÿคบ

namespace HappyDance
{
    // This allows us to call +Let+ directly
    using static LetTestHelper.LetHelper;

    [TestFixture]
    public class ArticlesControllerTest
    {
        private UnitOfWork Work => Let(() => new UnitOfWork());

        // We can depend on other Lets
        private Mock<IArticlesService> MockArticlesService => Let(() => new Mock<IArticlesService>(Work));

        // It's so easy, why not move it here too
        private ArticlesController Controller => Let(() => new ArticlesController(MockArticlesService.Object);

        [TearDown]
        public void AfterEach()
        {
            // You may cry, but only once (see below ๐Ÿ‘‡)
            LetTestHelper.LetHelper.Flush();
        }

        [Test]
        public void IndexShouldLoadPublishedArticles()
        {
            Controller.Index();
            MockArticlesService.Verify(service => service.Published(), Times.Once);
        }
    }
}

Flush the Cache ๐Ÿšฝ

  • After each test you will need to manually flush the results. My recommendation is creating a test helper that will flush the cache on tear down.
namespace MyProject.TestHelper
{
    [TestFixture]
    public class TestBase
    {
        [TearDown]
        public void Clean_LetHelper()
        {
            LetTestHelper.LetHelper.Flush();
        }
    }
}

Inspiration

Coming from Ruby I found instance management in C# to be, well, not fun. This is is influenced by RSpec let.

let.cs's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

let.cs's Issues

An expression tree may not contain an assignment operator

I like the library! I'm new to C#, and I miss some of the sugar of ruby libraries, especially rspec's let.

I hand-rolled my own version of NBuilder, and was saddened to see that it made things incompatible with this library.

private Client client => Let(() => {
    return clientSeeder.Build().With(
        c => c.ClientName = "Main Client"
    ).Persist();
});

An expression tree may not contain an assignment operator

This isn't an issue, I just wanted to leave it here for the record.

add simple IoC

I find myself creating Let definitions that are dependent on multiple objects throughout the tests. For instance, all service classes may require a DbContext and a CurrentUserContext. These are often times centralized in a parent TestBaseand used throughout all the tests and manually passed into the construction class under test. The benefit is the class under test is explicitly defined and passing dependencies isn't unknown to the programmer albeit tedious.

My initial fear is that it will separate the class definitions and cause run time when executing tests due to the implicit nature of DI and I'm not sure if this would solve real problems since it wouldn't leverage the container defined in the application layer.

On the other hand, I don't like adding dozens of Let definitions to my tests that are used solely for the purpose of being passed into the class under test.

Definition Options

  1. either construct classes from other Let definitions automatically
  2. use Let() definitions that are explicitly defined for DI
  3. injectable classes are configured separate from definitions
  4. injectable classes are configured during the definition of the Let definition.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.