22

It seems that truffle test automatically invokes truffle deploy (aka truffle migrate).

As far as I'm concerned, these two functionalities are completely unrelated.

So I cannot quite figure out why Truffle works this way to begin with.

The docs do not seem to mention anything on this subject.

I would like to use truffle test for one thing and truffle deploy for another thing.

Is there any way to "tell" truffle test to avoid running truffle deploy?

Thank you!!!

5
  • In one of your comments below, you seem to suggest you've solved this - could you provide details as to how, please?
    – glowkeeper
    Commented Sep 15, 2019 at 15:29
  • @glowkeeper: It's explained in that same comment. Commented Sep 15, 2019 at 15:37
  • not really - any chance you could share some config'?
    – glowkeeper
    Commented Sep 15, 2019 at 15:45
  • Aha - think I've worked this out! In deploy script: ``` if ( network === 'rinkeby' ) { return } ``` Then, in test script: ``` this.contract = await BlahContract.at('0x48B98faB029Cd2c77afA780Ab94c2d4e2f4879dA'); ``` Then run: truffle test --network rinkeby ```
    – glowkeeper
    Commented Sep 15, 2019 at 16:02
  • @glowkeeper: I added that as an answer (since it's too long to be posted as a comment). Commented Sep 15, 2019 at 16:06

5 Answers 5

9

I ran into this issue as well, and it is indeed the intended behavior of truffle test: cleanroom behavior. Each run of truffle test redeploys the contracts. If it didn't, then saved state from a prior run could affect the results of a subsequent run, making your test suite non-deterministic.

But I wanted to preserve state between runs of truffle test. The suggested way to do this is documented as:

deployer.deploy(Contract, {overwrite: false})

Unfortunately, the above seems to fail in truffle 5.0.1 due to a parsing bug. So a workaround to force correct parsing is this:

deployer.deploy(Contract, {gas: 6720000, overwrite: false})

https://truffleframework.com/docs/truffle/testing/testing-your-contracts#clean-room-environment

Clean-room environment

Truffle provides a clean room environment when running your test files. When running your tests against Ganache or Truffle Develop, Truffle will use advanced snapshotting features to ensure your test files don't share state with each other. When running against other Ethereum clients like go-ethereum, Truffle will re-deploy all of your migrations at the beginning of every test file to ensure you have a fresh set of contracts to test against.

1
  • 1
    Nice answer, but it'd be even better if you linked to that parsing bug to see what's the status/workarounds/etc.
    – hmijail
    Commented Jul 2, 2019 at 9:33
6

It is really embarrassing, how narrow minded the truffle authors think. My tests run their own deployment that is used in the tests. In my case, the truffle migration includes the steps that data is copied from the old instance to the new instance of the main contract, then the old contract is destroyed. Unfortunately, here the snapshot does not help, the old instance is not restored and a defect instance remains in the contract's json file. So I have to prevent the migration scripts from running. So there are good reasons, why migration should be optional and configurable in truffle test!

I solved it in the following way:

  • run a second canache-cli with a separete network named test
  • if the truffle migrate script is in network test, do nothing
  • run truffle test with option --network test

In detail:

Add on top of migrations/2_contract the line:

module.exports = async function(deployer, network, accounts) {
  if (network == "test") return; // test maintains own contracts
  …
}

Add new network test to truffle-config.js:

…
networks: {
  …
  development: {
    host: "127.0.0.1",
    port: 8545,
    network_id: "*"
  },
  test: {
    host: "127.0.0.1",
    port: 8546,
    network_id: "*"
  }
}
…

Run a second canache-cli (besides the one running network development:

In one console, I run ganache for development, for my GUI tests:

ganache-cli -d --db ${HOME}/tmp/ganache/development -i 123456 -p 8545

In another console, I run a separate ganache for test:

ganache-cli -d --db ${HOME}/tmp/ganache/test -i 654321 -p 8546

That's it! Now I can run:

truffle migrate --reset

And

truffle test --network test

Without interferences.

2
  • 6
    I think its unfair to call the truffle creators "narrow minded".
    – pizzarob
    Commented Feb 21, 2020 at 16:57
  • It's fair to call them narrow minded. Inflexible and short-sighted are also appropriate adjectives. Lesson: If you make and publicize a library, then make it highly configurable and modular. Avoid being opinionated . New smart contract devs, trying to make sense of smart contracts are blind-sided by poorly documented constraints that interfere with learning what the universal building blocks and protocols are.
    – devdanke
    Commented Feb 7, 2023 at 13:30
4

The truffle test command-line uses the development network configuration.

In other words, it is in fact equivalent to truffle test network=development.

So I solved this problem by adding in each one of the migration scripts in my project:

module.exports = function(deployer, network, accounts) {
    // encapsulate everything with this `if` statement
    if (network == "production") {
        ...
    }
};

Thus, everything inside the if statement is not executed when running truffle test.

And in order to keep the option of deploying my contracts with Truffle, I added this in my Truffle configuration file (truffle.js or truffle-config.js):

    production: {
        host:       "localhost", // for example
        port:       7545,        // for example
        network_id: "*",         // for example
        gasPrice:   20000000000, // for example
        gas:        6721975      // for example
    }

Which allows me to deploy my contracts via either one of the following command lines:

  • truffle deploy --network=production
  • truffle migrate --network=production
1

Before you can run any test, one has to define the starting point, the starting conditions in the smart contract. - Think about the values of the variable in the smart contracts. These conditions are defined by the deployment process. Hence, usually one would first run the deployment before testing. Also, this allows resetting the blockchain easily after each separate test.

If you do not want to do this, you might wanna try truffle scripts. They allow you to run any script or test.

6
  • 1
    Thank you. No, I would like to use truffle test because it provides a good report. I would like to create/deploy contracts myself - different contracts on each test. And most certainly not the same ones for every test. In some of my tests I use mockup contracts, with the purpose of testing a single contract in an isolated manner (aka unitest). In the migration script passed to truffle deploy, I would like to do "the real thing", since here my intention is not to test the contracts but to actually deploy them. Commented May 28, 2018 at 11:26
  • Then you might wanna use flags for the deployment: truffleframework.com/docs/advanced/configuration If no flag is passed, you simply do not execute any deployment code. Then truffle test runs through without deploying. If you hand over --network "testnetName" you could execute the deployment in the migration.
    – josojo
    Commented May 28, 2018 at 15:25
  • That's exactly how I ended up solving it, BTW (execute only if network == "production"). Thanks. Commented May 28, 2018 at 17:35
  • 1
    Though I wouldn't call them "flags", there are indeed 3 parameters passed to the script - deployer, network and accounts. Commented May 28, 2018 at 17:37
  • I have the same requirement - before I start developing frontend code for already deployed contracts, I wanna run some tests to make sure they work correctly! @josojo - can you share exactly how you would have 'without flags' working, please?
    – glowkeeper
    Commented Sep 15, 2019 at 15:30
1

For those wondering on a solution, here's the one hinted at in the comments above:

First, truffle-config.js looks something like this:

module.exports = {
  networks: {
    rinkeby: {
      host: "localhost", // Connect to geth on the specified
      port: 8545,
      from: "0x8f03ca885434522d695735a28d6a8a93b4390da9", // default address to use for any transaction Truffle makes during migrations
      network_id: 4,
      gas: 4612388 // Gas limit used for deploys
    }
};

Then, in the 2_deploy... script:

if ( network === 'rinkeby' ) 
{ 
  return 
} 

Finally, in your test script:

this.contract = await BlahContract.at('0x48B98faB029Cd2c77afA780Ab94c2d4e2f4879dA') 

Then run: truffle test --network rinkeby

Obviously, you will need some Rinkeby ether and you will need to unlock an account, with something like personal.unlockAccount(eth.coinbase, "yourPassword", 3000); from the geth console, but I have this method working for me. Yay :)

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.